From 7172c64a7cee4dfa95864f49c914f7ea8cf497c8 Mon Sep 17 00:00:00 2001 From: Marc Fiuczynski Date: Mon, 13 Nov 2006 19:54:30 +0000 Subject: [PATCH] Merge to Fedora kernel-2.6.18-1.2239_FC5 patched with stable patch-2.6.18.2-vs2.0.2.2-rc6.diff --- .config | 28 +- .config.old | 5 +- arch/i386/mach-voyager/voyager_thread.c | 1 - arch/s390/kernel/compat_signal.c | 1 - arch/s390/kernel/ptrace.c | 600 ---------------------- arch/sparc64/solaris/misc.c | 3 +- arch/um/kernel/exec.c | 9 +- configs/kernel-2.6.18-i586-smp.config | 10 +- configs/kernel-2.6.18-i586.config | 10 +- configs/kernel-2.6.18-i686-kdump.config | 28 +- configs/kernel-2.6.18-i686-smp.config | 28 +- configs/kernel-2.6.18-i686-xen.config | 26 +- configs/kernel-2.6.18-i686-xen0.config | 26 +- configs/kernel-2.6.18-i686-xenU.config | 8 +- configs/kernel-2.6.18-i686.config | 28 +- configs/kernel-2.6.18-ia64-xen.config | 32 +- configs/kernel-2.6.18-ia64.config | 28 +- configs/kernel-2.6.18-ppc-smp.config | 28 +- configs/kernel-2.6.18-ppc.config | 28 +- configs/kernel-2.6.18-ppc64-kdump.config | 28 +- configs/kernel-2.6.18-ppc64.config | 28 +- configs/kernel-2.6.18-ppc64iseries.config | 10 +- configs/kernel-2.6.18-s390.config | 4 +- configs/kernel-2.6.18-s390x.config | 4 +- configs/kernel-2.6.18-x86_64-kdump.config | 28 +- configs/kernel-2.6.18-x86_64-xen.config | 26 +- configs/kernel-2.6.18-x86_64-xen0.config | 26 +- configs/kernel-2.6.18-x86_64-xenU.config | 8 +- configs/kernel-2.6.18-x86_64.config | 28 +- drivers/char/selection.c | 2 +- drivers/char/tty_io.c | 283 +++++----- drivers/char/tty_ioctl.c | 35 +- drivers/char/vt.c | 12 +- drivers/char/vt_ioctl.c | 17 +- drivers/isdn/capi/capidrv.c | 3 +- drivers/isdn/hisax/config.c | 6 +- drivers/isdn/icn/icn.c | 3 +- drivers/isdn/isdnloop/isdnloop.c | 3 +- drivers/isdn/pcbit/drv.c | 16 +- drivers/net/e1000/e1000_main.c | 8 + drivers/net/forcedeth.c | 48 ++ drivers/net/wan/pc300.h | 1 + drivers/s390/char/fs3270.c | 12 +- drivers/s390/char/tty3270.c | 1 - fs/buffer.c | 21 +- fs/cifs/inode.c | 4 +- fs/cramfs/inode.c | 2 + fs/dquot.c | 17 +- fs/nfs/direct.c | 12 +- fs/open.c | 1 + fs/proc/array.c | 3 + fs/splice.c | 37 +- include/linux/tracehook.h | 2 +- include/linux/tty.h | 43 +- include/linux/utrace.h | 2 +- include/linux/vs_cvirt.h | 1 + include/linux/vt_kern.h | 3 +- kernel/acct.c | 9 +- kernel/auditsc.c | 7 + kernel/exit.c | 4 +- kernel/ptrace.c | 2 - kernel/sys.c | 6 +- kernel/utrace.c | 339 ++++++++---- mm/migrate.c | 3 +- security/selinux/hooks.c | 14 +- 65 files changed, 788 insertions(+), 1311 deletions(-) diff --git a/.config b/.config index 813a75a45..867d51505 100644 --- a/.config +++ b/.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:43 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:02 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -177,9 +177,9 @@ CONFIG_KEXEC=y CONFIG_PHYSICAL_START=0x200000 # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_REORDER=y CONFIG_K8_NB=y CONFIG_GENERIC_HARDIRQS=y @@ -1973,23 +1973,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/.config.old b/.config.old index e5440ae00..90ead9a07 100644 --- a/.config.old +++ b/.config.old @@ -1591,7 +1591,7 @@ CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_W83791D=m CONFIG_SENSORS_W83792D=m -CONFIG_W1=m +# CONFIG_W1 is not set CONFIG_W1_MASTER_MATROX=m CONFIG_W1_MASTER_DS2482=m CONFIG_W1_SLAVE_THERM=m @@ -2868,6 +2868,9 @@ CONFIG_CACHEFILES_DEBUG=y CONFIG_NFS_FSCACHE=y # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set + +CONFIG_HZ_1000=y + CONFIG_UID16=y # CONFIG_X86_64_XEN is not set # CONFIG_MK8 is not set diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c index 50f6de6ff..f39887359 100644 --- a/arch/i386/mach-voyager/voyager_thread.c +++ b/arch/i386/mach-voyager/voyager_thread.c @@ -130,7 +130,6 @@ thread(void *unused) init_timer(&wakeup_timer); sigfillset(¤t->blocked); - current->signal->tty = NULL; printk(KERN_NOTICE "Voyager starting monitor thread\n"); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index bdb86e759..310d16891 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -586,4 +586,3 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka, return ret; } - diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 74c313365..395bd3a50 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -680,606 +680,6 @@ fastcall int arch_compat_ptrace(compat_long_t *request, #endif /* CONFIG_PTRACE */ -#if 0 /* XXX */ - -#ifndef CONFIG_64BIT -# define __ADDR_MASK 3 -#else -# define __ADDR_MASK 7 -#endif - -/* - * Read the word at offset addr from the user area of a process. The - * trouble here is that the information is littered over different - * locations. The process registers are found on the kernel stack, - * the floating point stuff and the trace settings are stored in - * the task structure. In addition the different structures in - * struct user contain pad bytes that should be read as zeroes. - * Lovely... - */ -static int -peek_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t offset, tmp, mask; - - /* - * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell... - */ - mask = __ADDR_MASK; -#ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) - mask = 3; -#endif - if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) - return -EIO; - - if (addr < (addr_t) &dummy->regs.acrs) { - /* - * psw and gprs are stored on the stack - */ - tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); - if (addr == (addr_t) &dummy->regs.psw.mask) - /* Remove per bit from user psw. */ - tmp &= ~PSW_MASK_PER; - - } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { - /* - * access registers are stored in the thread structure - */ - offset = addr - (addr_t) &dummy->regs.acrs; -#ifdef CONFIG_64BIT - /* - * Very special case: old & broken 64 bit gdb reading - * from acrs[15]. Result is a 64 bit value. Read the - * 32 bit acrs[15] value and shift it by 32. Sick... - */ - if (addr == (addr_t) &dummy->regs.acrs[15]) - tmp = ((unsigned long) child->thread.acrs[15]) << 32; - else -#endif - tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); - - } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { - /* - * orig_gpr2 is stored on the kernel stack - */ - tmp = (addr_t) task_pt_regs(child)->orig_gpr2; - - } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { - /* - * floating point regs. are stored in the thread structure - */ - offset = addr - (addr_t) &dummy->regs.fp_regs; - tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); - if (addr == (addr_t) &dummy->regs.fp_regs.fpc) - tmp &= (unsigned long) FPC_VALID_MASK - << (BITS_PER_LONG - 32); - - } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { - /* - * per_info is found in the thread structure - */ - offset = addr - (addr_t) &dummy->regs.per_info; - tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset); - - } else - tmp = 0; - - return put_user(tmp, (addr_t __user *) data); -} - -/* - * Write a word to the user area of a process at location addr. This - * operation does have an additional problem compared to peek_user. - * Stores to the program status word and on the floating point - * control register needs to get checked for validity. - */ -static int -poke_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t offset, mask; - - /* - * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell indeed... - */ - mask = __ADDR_MASK; -#ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) - mask = 3; -#endif - if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) - return -EIO; - - if (addr < (addr_t) &dummy->regs.acrs) { - /* - * psw and gprs are stored on the stack - */ - if (addr == (addr_t) &dummy->regs.psw.mask && -#ifdef CONFIG_COMPAT - data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && -#endif - data != PSW_MASK_MERGE(PSW_USER_BITS, data)) - /* Invalid psw mask. */ - return -EINVAL; -#ifndef CONFIG_64BIT - if (addr == (addr_t) &dummy->regs.psw.addr) - /* I'd like to reject addresses without the - high order bit but older gdb's rely on it */ - data |= PSW_ADDR_AMODE; -#endif - *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; - - } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { - /* - * access registers are stored in the thread structure - */ - offset = addr - (addr_t) &dummy->regs.acrs; -#ifdef CONFIG_64BIT - /* - * Very special case: old & broken 64 bit gdb writing - * to acrs[15] with a 64 bit value. Ignore the lower - * half of the value and write the upper 32 bit to - * acrs[15]. Sick... - */ - if (addr == (addr_t) &dummy->regs.acrs[15]) - child->thread.acrs[15] = (unsigned int) (data >> 32); - else -#endif - *(addr_t *)((addr_t) &child->thread.acrs + offset) = data; - - } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { - /* - * orig_gpr2 is stored on the kernel stack - */ - task_pt_regs(child)->orig_gpr2 = data; - - } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { - /* - * floating point regs. are stored in the thread structure - */ - if (addr == (addr_t) &dummy->regs.fp_regs.fpc && - (data & ~((unsigned long) FPC_VALID_MASK - << (BITS_PER_LONG - 32))) != 0) - return -EINVAL; - offset = addr - (addr_t) &dummy->regs.fp_regs; - *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; - - } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { - /* - * per_info is found in the thread structure - */ - offset = addr - (addr_t) &dummy->regs.per_info; - *(addr_t *)((addr_t) &child->thread.per_info + offset) = data; - - } - - FixPerRegisters(child); - return 0; -} - -static int -do_ptrace_normal(struct task_struct *child, long request, long addr, long data) -{ - unsigned long tmp; - ptrace_area parea; - int copied, ret; - - switch (request) { - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* read word at location addr. */ - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - if (copied != sizeof(tmp)) - return -EIO; - return put_user(tmp, (unsigned long __user *) data); - - case PTRACE_PEEKUSR: - /* read the word at location addr in the USER area. */ - return peek_user(child, addr, data); - - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* write the word at location addr. */ - copied = access_process_vm(child, addr, &data, sizeof(data),1); - if (copied != sizeof(data)) - return -EIO; - return 0; - - case PTRACE_POKEUSR: - /* write the word at location addr in the USER area */ - return poke_user(child, addr, data); - - case PTRACE_PEEKUSR_AREA: - case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, - sizeof(parea))) - return -EFAULT; - addr = parea.kernel_addr; - data = parea.process_addr; - copied = 0; - while (copied < parea.len) { - if (request == PTRACE_PEEKUSR_AREA) - ret = peek_user(child, addr, data); - else { - addr_t tmp; - if (get_user (tmp, (addr_t __user *) data)) - return -EFAULT; - ret = poke_user(child, addr, tmp); - } - if (ret) - return ret; - addr += sizeof(unsigned long); - data += sizeof(unsigned long); - copied += sizeof(unsigned long); - } - return 0; - } - return ptrace_request(child, request, addr, data); -} - -#ifdef CONFIG_COMPAT -/* - * Now the fun part starts... a 31 bit program running in the - * 31 bit emulation tracing another program. PTRACE_PEEKTEXT, - * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy - * to handle, the difference to the 64 bit versions of the requests - * is that the access is done in multiples of 4 byte instead of - * 8 bytes (sizeof(unsigned long) on 31/64 bit). - * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA, - * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program - * is a 31 bit program too, the content of struct user can be - * emulated. A 31 bit program peeking into the struct user of - * a 64 bit program is a no-no. - */ - -/* - * Same as peek_user but for a 31 bit program. - */ -static int -peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user32 *dummy32 = NULL; - per_struct32 *dummy_per32 = NULL; - addr_t offset; - __u32 tmp; - - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user) - 3) - return -EIO; - - if (addr < (addr_t) &dummy32->regs.acrs) { - /* - * psw and gprs are stored on the stack - */ - if (addr == (addr_t) &dummy32->regs.psw.mask) { - /* Fake a 31 bit psw mask. */ - tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); - tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); - } else if (addr == (addr_t) &dummy32->regs.psw.addr) { - /* Fake a 31 bit psw address. */ - tmp = (__u32) task_pt_regs(child)->psw.addr | - PSW32_ADDR_AMODE31; - } else { - /* gpr 0-15 */ - tmp = *(__u32 *)((addr_t) &task_pt_regs(child)->psw + - addr*2 + 4); - } - } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { - /* - * access registers are stored in the thread structure - */ - offset = addr - (addr_t) &dummy32->regs.acrs; - tmp = *(__u32*)((addr_t) &child->thread.acrs + offset); - - } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { - /* - * orig_gpr2 is stored on the kernel stack - */ - tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); - - } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { - /* - * floating point regs. are stored in the thread structure - */ - offset = addr - (addr_t) &dummy32->regs.fp_regs; - tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); - - } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { - /* - * per_info is found in the thread structure - */ - offset = addr - (addr_t) &dummy32->regs.per_info; - /* This is magic. See per_struct and per_struct32. */ - if ((offset >= (addr_t) &dummy_per32->control_regs && - offset < (addr_t) (&dummy_per32->control_regs + 1)) || - (offset >= (addr_t) &dummy_per32->starting_addr && - offset <= (addr_t) &dummy_per32->ending_addr) || - offset == (addr_t) &dummy_per32->lowcore.words.address) - offset = offset*2 + 4; - else - offset = offset*2; - tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset); - - } else - tmp = 0; - - return put_user(tmp, (__u32 __user *) data); -} - -/* - * Same as poke_user but for a 31 bit program. - */ -static int -poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user32 *dummy32 = NULL; - per_struct32 *dummy_per32 = NULL; - addr_t offset; - __u32 tmp; - - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user32) - 3) - return -EIO; - - tmp = (__u32) data; - - if (addr < (addr_t) &dummy32->regs.acrs) { - /* - * psw, gprs, acrs and orig_gpr2 are stored on the stack - */ - if (addr == (addr_t) &dummy32->regs.psw.mask) { - /* Build a 64 bit psw mask from 31 bit mask. */ - if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) - /* Invalid psw mask. */ - return -EINVAL; - task_pt_regs(child)->psw.mask = - PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); - } else if (addr == (addr_t) &dummy32->regs.psw.addr) { - /* Build a 64 bit psw address from 31 bit address. */ - task_pt_regs(child)->psw.addr = - (__u64) tmp & PSW32_ADDR_INSN; - } else { - /* gpr 0-15 */ - *(__u32*)((addr_t) &task_pt_regs(child)->psw - + addr*2 + 4) = tmp; - } - } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { - /* - * access registers are stored in the thread structure - */ - offset = addr - (addr_t) &dummy32->regs.acrs; - *(__u32*)((addr_t) &child->thread.acrs + offset) = tmp; - - } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { - /* - * orig_gpr2 is stored on the kernel stack - */ - *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; - - } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { - /* - * floating point regs. are stored in the thread structure - */ - if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && - (tmp & ~FPC_VALID_MASK) != 0) - /* Invalid floating point control. */ - return -EINVAL; - offset = addr - (addr_t) &dummy32->regs.fp_regs; - *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; - - } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { - /* - * per_info is found in the thread structure. - */ - offset = addr - (addr_t) &dummy32->regs.per_info; - /* - * This is magic. See per_struct and per_struct32. - * By incident the offsets in per_struct are exactly - * twice the offsets in per_struct32 for all fields. - * The 8 byte fields need special handling though, - * because the second half (bytes 4-7) is needed and - * not the first half. - */ - if ((offset >= (addr_t) &dummy_per32->control_regs && - offset < (addr_t) (&dummy_per32->control_regs + 1)) || - (offset >= (addr_t) &dummy_per32->starting_addr && - offset <= (addr_t) &dummy_per32->ending_addr) || - offset == (addr_t) &dummy_per32->lowcore.words.address) - offset = offset*2 + 4; - else - offset = offset*2; - *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp; - - } - - FixPerRegisters(child); - return 0; -} - -static int -do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) -{ - unsigned int tmp; /* 4 bytes !! */ - ptrace_area_emu31 parea; - int copied, ret; - - switch (request) { - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - /* read word at location addr. */ - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - if (copied != sizeof(tmp)) - return -EIO; - return put_user(tmp, (unsigned int __user *) data); - - case PTRACE_PEEKUSR: - /* read the word at location addr in the USER area. */ - return peek_user_emu31(child, addr, data); - - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - /* write the word at location addr. */ - tmp = data; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); - if (copied != sizeof(tmp)) - return -EIO; - return 0; - - case PTRACE_POKEUSR: - /* write the word at location addr in the USER area */ - return poke_user_emu31(child, addr, data); - - case PTRACE_PEEKUSR_AREA: - case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, - sizeof(parea))) - return -EFAULT; - addr = parea.kernel_addr; - data = parea.process_addr; - copied = 0; - while (copied < parea.len) { - if (request == PTRACE_PEEKUSR_AREA) - ret = peek_user_emu31(child, addr, data); - else { - __u32 tmp; - if (get_user (tmp, (__u32 __user *) data)) - return -EFAULT; - ret = poke_user_emu31(child, addr, tmp); - } - if (ret) - return ret; - addr += sizeof(unsigned int); - data += sizeof(unsigned int); - copied += sizeof(unsigned int); - } - return 0; -#if 0 /* XXX */ - case PTRACE_GETEVENTMSG: - return put_user((__u32) child->ptrace_message, - (unsigned int __user *) data); - case PTRACE_GETSIGINFO: - if (child->last_siginfo == NULL) - return -EINVAL; - return copy_siginfo_to_user32((compat_siginfo_t __user *) data, - child->last_siginfo); - case PTRACE_SETSIGINFO: - if (child->last_siginfo == NULL) - return -EINVAL; - return copy_siginfo_from_user32(child->last_siginfo, - (compat_siginfo_t __user *) data); -#endif - } - return ptrace_request(child, request, addr, data); -} -#endif - -#define PT32_IEEE_IP 0x13c - -static int -do_ptrace(struct task_struct *child, long request, long addr, long data) -{ - int ret; - - if (request == PTRACE_ATTACH) - return ptrace_attach(child); - - /* - * Special cases to get/store the ieee instructions pointer. - */ - if (child == current) { - if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP) - return peek_user(child, addr, data); - if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP) - return poke_user(child, addr, data); -#ifdef CONFIG_COMPAT - if (request == PTRACE_PEEKUSR && - addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) - return peek_user_emu31(child, addr, data); - if (request == PTRACE_POKEUSR && - addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) - return poke_user_emu31(child, addr, data); -#endif - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - return ret; - - switch (request) { - case PTRACE_SYSCALL: - /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: - /* restart after signal. */ - if (!valid_signal(data)) - return -EIO; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - /* make sure the single step bit is not set. */ - tracehook_disable_single_step(child); - wake_up_process(child); - return 0; - - case PTRACE_KILL: - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - return 0; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - tracehook_disable_single_step(child); - wake_up_process(child); - return 0; - - case PTRACE_SINGLESTEP: - /* set the trap flag. */ - if (!valid_signal(data)) - return -EIO; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - if (data) - set_tsk_thread_flag(child, TIF_SINGLE_STEP); - else - tracehook_enable_single_step(child); - /* give it a chance to run. */ - wake_up_process(child); - return 0; - - case PTRACE_DETACH: - /* detach a process that was attached. */ - return ptrace_detach(child, data); - - - /* Do requests that differ for 31/64 bit */ - default: -#ifdef CONFIG_COMPAT - if (test_thread_flag(TIF_31BIT)) - return do_ptrace_emu31(child, request, addr, data); -#endif - return do_ptrace_normal(child, request, addr, data); - } - /* Not reached. */ - return -EIO; -} -#endif - - - asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) { diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index a7f0dacf4..ebd420743 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -423,7 +424,7 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) Solaris setpgrp and setsid? */ ret = sys_setpgid(0, 0); if (ret) return ret; - current->signal->tty = NULL; + proc_clear_tty(current); return process_group(current); } case 2: /* getsid */ diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index fc38a6d59..8d56ec6cc 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -39,11 +39,14 @@ static long execve1(char *file, char __user * __user *argv, char __user *__user *env) { long error; + struct tty_struct *tty; #ifdef CONFIG_TTY_LOG - task_lock(current); - log_exec(argv, current->signal->tty); - task_unlock(current); + mutex_lock(&tty_mutex); + tty = get_current_tty(); + if (tty) + log_exec(argv, tty); + mutex_unlock(&tty_mutex); #endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ diff --git a/configs/kernel-2.6.18-i586-smp.config b/configs/kernel-2.6.18-i586-smp.config index 224fc97d5..61a83171d 100644 --- a/configs/kernel-2.6.18-i586-smp.config +++ b/configs/kernel-2.6.18-i586-smp.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:39 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:57 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -212,9 +212,9 @@ CONFIG_BOOT_IOREMAP=y CONFIG_REGPARM=y # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x400000 diff --git a/configs/kernel-2.6.18-i586.config b/configs/kernel-2.6.18-i586.config index 906c52ba2..f47689d56 100644 --- a/configs/kernel-2.6.18-i586.config +++ b/configs/kernel-2.6.18-i586.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:39 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:57 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -202,9 +202,9 @@ CONFIG_BOOT_IOREMAP=y CONFIG_REGPARM=y # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x400000 diff --git a/configs/kernel-2.6.18-i686-kdump.config b/configs/kernel-2.6.18-i686-kdump.config index 8e2ca42b6..d42285daa 100644 --- a/configs/kernel-2.6.18-i686-kdump.config +++ b/configs/kernel-2.6.18-i686-kdump.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:39 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:57 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -209,9 +209,9 @@ CONFIG_BOOT_IOREMAP=y CONFIG_REGPARM=y # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y CONFIG_PHYSICAL_START=0x1000000 @@ -2171,23 +2171,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-i686-smp.config b/configs/kernel-2.6.18-i686-smp.config index 00cc6b483..52cad3423 100644 --- a/configs/kernel-2.6.18-i686-smp.config +++ b/configs/kernel-2.6.18-i686-smp.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:40 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:58 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -213,9 +213,9 @@ CONFIG_BOOT_IOREMAP=y CONFIG_REGPARM=y # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x400000 @@ -2169,23 +2169,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-i686-xen.config b/configs/kernel-2.6.18-i686-xen.config index b6af8017a..d01024b43 100644 --- a/configs/kernel-2.6.18-i686-xen.config +++ b/configs/kernel-2.6.18-i686-xen.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:40 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:58 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -2023,23 +2023,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -3213,8 +3197,8 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-i686-xen0.config b/configs/kernel-2.6.18-i686-xen0.config index c6fe1ef9d..71aa7cc9e 100644 --- a/configs/kernel-2.6.18-i686-xen0.config +++ b/configs/kernel-2.6.18-i686-xen0.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:40 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:58 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -2021,23 +2021,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -3211,8 +3195,8 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-i686-xenU.config b/configs/kernel-2.6.18-i686-xenU.config index 309644b0c..50ea265a7 100644 --- a/configs/kernel-2.6.18-i686-xenU.config +++ b/configs/kernel-2.6.18-i686-xenU.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:40 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:58 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -1590,8 +1590,8 @@ CONFIG_XEN_BLKDEV_TAP=m # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-i686.config b/configs/kernel-2.6.18-i686.config index 96690dc15..f11ce5410 100644 --- a/configs/kernel-2.6.18-i686.config +++ b/configs/kernel-2.6.18-i686.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:41 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:58 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -208,9 +208,9 @@ CONFIG_BOOT_IOREMAP=y CONFIG_REGPARM=y # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x400000 @@ -2171,23 +2171,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ia64-xen.config b/configs/kernel-2.6.18-ia64-xen.config index 7fea409eb..f701d613c 100644 --- a/configs/kernel-2.6.18-ia64-xen.config +++ b/configs/kernel-2.6.18-ia64-xen.config @@ -1,8 +1,8 @@ # ia64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:41 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:59 2006 # CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -1718,23 +1718,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -2019,9 +2003,9 @@ CONFIG_USB_DABUSB=m # # CONFIG_FIRMWARE_EDID is not set CONFIG_FB=y -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set CONFIG_FB_MODE_HELPERS=y @@ -2871,8 +2855,8 @@ CONFIG_XEN_NETDEV_LOOPBACK=m # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-ia64.config b/configs/kernel-2.6.18-ia64.config index e6c8653c4..7b62204a1 100644 --- a/configs/kernel-2.6.18-ia64.config +++ b/configs/kernel-2.6.18-ia64.config @@ -1,8 +1,8 @@ # ia64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:41 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:59 2006 # CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -123,9 +123,9 @@ CONFIG_IA64_PAGE_SIZE_16KB=y CONFIG_PGTABLE_3=y # CONFIG_PGTABLE_4 is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_IA64_L1_CACHE_SHIFT=7 CONFIG_IA64_CYCLONE=y CONFIG_IOSAPIC=y @@ -1763,23 +1763,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ppc-smp.config b/configs/kernel-2.6.18-ppc-smp.config index 66147ea3d..1e88dacdc 100644 --- a/configs/kernel-2.6.18-ppc-smp.config +++ b/configs/kernel-2.6.18-ppc-smp.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:41 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:31:59 2006 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -176,9 +176,9 @@ CONFIG_MPIC=y # CONFIG_HIGHMEM=y # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set @@ -1993,23 +1993,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ppc.config b/configs/kernel-2.6.18-ppc.config index 1db169fcf..4105f9639 100644 --- a/configs/kernel-2.6.18-ppc.config +++ b/configs/kernel-2.6.18-ppc.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:41 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:00 2006 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -173,9 +173,9 @@ CONFIG_MPIC=y # CONFIG_HIGHMEM=y # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set @@ -1997,23 +1997,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ppc64-kdump.config b/configs/kernel-2.6.18-ppc64-kdump.config index aba782700..00a75efd0 100644 --- a/configs/kernel-2.6.18-ppc64-kdump.config +++ b/configs/kernel-2.6.18-ppc64-kdump.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:00 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -181,9 +181,9 @@ CONFIG_CBE_RAS=y # Kernel options # # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set @@ -1887,23 +1887,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ppc64.config b/configs/kernel-2.6.18-ppc64.config index 7b31ef807..885dfeccd 100644 --- a/configs/kernel-2.6.18-ppc64.config +++ b/configs/kernel-2.6.18-ppc64.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:00 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -181,9 +181,9 @@ CONFIG_CBE_RAS=y # Kernel options # # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set @@ -1887,23 +1887,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-ppc64iseries.config b/configs/kernel-2.6.18-ppc64iseries.config index ffeabee01..22f751443 100644 --- a/configs/kernel-2.6.18-ppc64iseries.config +++ b/configs/kernel-2.6.18-ppc64iseries.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:00 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -147,9 +147,9 @@ CONFIG_IBMVIO=y # Kernel options # # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set diff --git a/configs/kernel-2.6.18-s390.config b/configs/kernel-2.6.18-s390.config index 971ecd194..9853ff344 100644 --- a/configs/kernel-2.6.18-s390.config +++ b/configs/kernel-2.6.18-s390.config @@ -1,8 +1,8 @@ # s390 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:00 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y diff --git a/configs/kernel-2.6.18-s390x.config b/configs/kernel-2.6.18-s390x.config index 6340b1bce..25dc399df 100644 --- a/configs/kernel-2.6.18-s390x.config +++ b/configs/kernel-2.6.18-s390x.config @@ -1,8 +1,8 @@ # s390 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:01 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y diff --git a/configs/kernel-2.6.18-x86_64-kdump.config b/configs/kernel-2.6.18-x86_64-kdump.config index e62073eff..f9b450d02 100644 --- a/configs/kernel-2.6.18-x86_64-kdump.config +++ b/configs/kernel-2.6.18-x86_64-kdump.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:42 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:01 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -161,9 +161,9 @@ CONFIG_CRASH_DUMP=y CONFIG_PHYSICAL_START=0x1000000 # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_REORDER=y CONFIG_K8_NB=y CONFIG_GENERIC_HARDIRQS=y @@ -1961,23 +1961,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/configs/kernel-2.6.18-x86_64-xen.config b/configs/kernel-2.6.18-x86_64-xen.config index b4a0c30c0..efb0ffc4a 100644 --- a/configs/kernel-2.6.18-x86_64-xen.config +++ b/configs/kernel-2.6.18-x86_64-xen.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:43 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:01 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -1935,23 +1935,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -3107,8 +3091,8 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-x86_64-xen0.config b/configs/kernel-2.6.18-x86_64-xen0.config index 25d6f9044..18ad8c72e 100644 --- a/configs/kernel-2.6.18-x86_64-xen0.config +++ b/configs/kernel-2.6.18-x86_64-xen0.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:43 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:01 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -1935,23 +1935,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -3107,8 +3091,8 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-x86_64-xenU.config b/configs/kernel-2.6.18-x86_64-xenU.config index 78ffb6490..ed4279c00 100644 --- a/configs/kernel-2.6.18-x86_64-xenU.config +++ b/configs/kernel-2.6.18-x86_64-xenU.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:43 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:01 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -1546,8 +1546,8 @@ CONFIG_XEN_BLKDEV_TAP=m # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_KEYBOARD=y +# CONFIG_XEN_FRAMEBUFFER is not set +# CONFIG_XEN_KEYBOARD is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/configs/kernel-2.6.18-x86_64.config b/configs/kernel-2.6.18-x86_64.config index 16135f6c2..99308ef8b 100644 --- a/configs/kernel-2.6.18-x86_64.config +++ b/configs/kernel-2.6.18-x86_64.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2-rc1 -# Mon Nov 13 09:44:43 2006 +# Linux kernel version: 2.6.18.2 +# Mon Nov 13 09:32:02 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -178,9 +178,9 @@ CONFIG_KEXEC=y CONFIG_PHYSICAL_START=0x200000 # CONFIG_SECCOMP is not set # CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 CONFIG_REORDER=y CONFIG_K8_NB=y CONFIG_GENERIC_HARDIRQS=y @@ -1974,23 +1974,7 @@ CONFIG_SENSORS_MAX6875=m # # Dallas's 1-wire bus # -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y +# CONFIG_W1 is not set # # Hardware Monitoring support diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 71093a9fc..74cff839c 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -33,7 +33,7 @@ extern void poke_blanked_console(void); /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ -struct vc_data *sel_cons; /* must not be disallocated */ +struct vc_data *sel_cons; /* must not be deallocated */ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 199e7f0cf..d70a25995 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -127,9 +127,10 @@ EXPORT_SYMBOL(tty_std_termios); LIST_HEAD(tty_drivers); /* linked list of tty drivers */ -/* Semaphore to protect creating and releasing a tty. This is shared with +/* Mutex to protect creating and releasing a tty. This is shared with vt.c for deeply disgusting hack reasons */ DEFINE_MUTEX(tty_mutex); +EXPORT_SYMBOL(tty_mutex); #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ @@ -161,17 +162,11 @@ static void release_mem(struct tty_struct *tty, int idx); * been initialized in any way but has been zeroed * * Locking: none - * FIXME: use kzalloc */ static struct tty_struct *alloc_tty_struct(void) { - struct tty_struct *tty; - - tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); - if (tty) - memset(tty, 0, sizeof(struct tty_struct)); - return tty; + return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); } static void tty_buffer_free_all(struct tty_struct *); @@ -256,7 +251,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) "!= #fd's(%d) in %s\n", tty->name, tty->count, count, routine); return count; - } + } #endif return 0; } @@ -265,18 +260,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) * Tty buffer allocation management */ - -/** - * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from - * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use - * - * Locking: none - */ - - /** * tty_buffer_free_all - free buffers used by a tty * @tty: tty to free from @@ -484,10 +467,9 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, tb->used += space; copied += space; chars += space; - } - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - while (unlikely(size > copied)); + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); return copied; } EXPORT_SYMBOL(tty_insert_flip_string); @@ -522,10 +504,9 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, copied += space; chars += space; flags += space; - } - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - while (unlikely(size > copied)); + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); return copied; } EXPORT_SYMBOL(tty_insert_flip_string_flags); @@ -622,14 +603,14 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); * they are not on hot paths so a little discipline won't do * any harm. * - * Locking: takes termios_sem + * Locking: takes termios_mutex */ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) { - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tty->termios->c_line = num; - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /* @@ -923,7 +904,7 @@ static void tty_ldisc_enable(struct tty_struct *tty) * context. * * Locking: takes tty_ldisc_lock. - * called functions take termios_sem + * called functions take termios_mutex */ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) @@ -1275,12 +1256,12 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * * Locking: * BKL - * redirect lock for undoing redirection - * file list lock for manipulating list of ttys - * tty_ldisc_lock from called functions - * termios_sem resetting termios data - * tasklist_lock to walk task list for hangup event - * + * redirect lock for undoing redirection + * file list lock for manipulating list of ttys + * tty_ldisc_lock from called functions + * termios_mutex resetting termios data + * tasklist_lock to walk task list for hangup event + * ->siglock to protect ->signal/->sighand */ static void do_tty_hangup(void *data) { @@ -1347,9 +1328,9 @@ static void do_tty_hangup(void *data) */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); *tty->termios = tty->driver->init_termios; - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /* Defer ldisc switch */ @@ -1361,14 +1342,18 @@ static void do_tty_hangup(void *data) read_lock(&tasklist_lock); if (tty->session > 0) { do_each_task_pid(tty->session, PIDTYPE_SID, p) { + spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) p->signal->tty = NULL; - if (!p->signal->leader) + if (!p->signal->leader) { + spin_unlock_irq(&p->sighand->siglock); continue; - group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); - group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); + } + __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); + __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); if (tty->pgrp > 0) p->signal->tty_old_pgrp = tty->pgrp; + spin_unlock_irq(&p->sighand->siglock); } while_each_task_pid(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); @@ -1460,6 +1445,14 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); +static void session_clear_tty(pid_t session) +{ + struct task_struct *p; + do_each_task_pid(session, PIDTYPE_SID, p) { + proc_clear_tty(p); + } while_each_task_pid(session, PIDTYPE_SID, p); +} + /** * disassociate_ctty - disconnect controlling tty * @on_exit: true if exiting so need to "hang up" the session @@ -1476,31 +1469,35 @@ EXPORT_SYMBOL(tty_hung_up_p); * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. * - * Locking: tty_mutex is taken to protect current->signal->tty + * Locking: * BKL is taken for hysterical raisins - * Tasklist lock is taken (under tty_mutex) to walk process - * lists for the session. + * tty_mutex is taken to protect tty + * ->siglock is taken to protect ->signal/->sighand + * tasklist_lock is taken to walk process list for sessions + * ->siglock is taken to protect ->signal/->sighand */ void disassociate_ctty(int on_exit) { struct tty_struct *tty; - struct task_struct *p; int tty_pgrp = -1; + int session; lock_kernel(); mutex_lock(&tty_mutex); - tty = current->signal->tty; + tty = get_current_tty(); if (tty) { tty_pgrp = tty->pgrp; mutex_unlock(&tty_mutex); + /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { - if (current->signal->tty_old_pgrp) { - kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); - kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); + pid_t old_pgrp = current->signal->tty_old_pgrp; + if (old_pgrp) { + kill_pg(old_pgrp, SIGHUP, on_exit); + kill_pg(old_pgrp, SIGCONT, on_exit); } mutex_unlock(&tty_mutex); unlock_kernel(); @@ -1512,19 +1509,29 @@ void disassociate_ctty(int on_exit) kill_pg(tty_pgrp, SIGCONT, on_exit); } - /* Must lock changes to tty_old_pgrp */ - mutex_lock(&tty_mutex); + spin_lock_irq(¤t->sighand->siglock); current->signal->tty_old_pgrp = 0; - tty->session = 0; - tty->pgrp = -1; + session = current->signal->session; + spin_unlock_irq(¤t->sighand->siglock); + + mutex_lock(&tty_mutex); + /* It is possible that do_tty_hangup has free'd this tty */ + tty = get_current_tty(); + if (tty) { + tty->session = 0; + tty->pgrp = 0; + } else { +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "error attempted to write to tty [0x%p]" + " = NULL", tty); +#endif + } + mutex_unlock(&tty_mutex); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); - do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); + session_clear_tty(session); read_unlock(&tasklist_lock); - mutex_unlock(&tty_mutex); unlock_kernel(); } @@ -2343,16 +2350,10 @@ static void release_dev(struct file * filp) * tty. */ if (tty_closing || o_tty_closing) { - struct task_struct *p; - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); + session_clear_tty(tty->session); if (o_tty) - do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); + session_clear_tty(o_tty->session); read_unlock(&tasklist_lock); } @@ -2449,9 +2450,9 @@ static void release_dev(struct file * filp) * The termios state of a pty is reset on first open so that * settings don't persist across reuse. * - * Locking: tty_mutex protects current->signal->tty, get_tty_driver and - * init_dev work. tty->count should protect the rest. - * task_lock is held to update task details for sessions + * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. + * tty->count should protect the rest. + * ->siglock protects ->signal/->sighand */ static int tty_open(struct inode * inode, struct file * filp) @@ -2473,12 +2474,13 @@ retry_open: mutex_lock(&tty_mutex); if (device == MKDEV(TTYAUX_MAJOR,0)) { - if (!current->signal->tty) { + tty = get_current_tty(); + if (!tty) { mutex_unlock(&tty_mutex); return -ENXIO; } - driver = current->signal->tty->driver; - index = current->signal->tty->index; + driver = tty->driver; + index = tty->index; filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ goto got_driver; @@ -2553,17 +2555,16 @@ got_driver: filp->f_op = &tty_fops; goto retry_open; } + + mutex_lock(&tty_mutex); + spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && - tty->session == 0) { - task_lock(current); - current->signal->tty = tty; - task_unlock(current); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - } + tty->session == 0) + __proc_set_tty(current, tty); + spin_unlock_irq(¤t->sighand->siglock); + mutex_unlock(&tty_mutex); return 0; } @@ -2727,6 +2728,8 @@ static int tty_fasync(int fd, struct file * filp, int on) * Locking: * Called functions take tty_ldisc_lock * current->signal->tty check is safe without locks + * + * FIXME: may race normal receive processing */ static int tiocsti(struct tty_struct *tty, char __user *p) @@ -2749,18 +2752,21 @@ static int tiocsti(struct tty_struct *tty, char __user *p) * @tty; tty * @arg: user buffer for result * - * Copies the kernel idea of the window size into the user buffer. No - * locking is done. + * Copies the kernel idea of the window size into the user buffer. * - * FIXME: Returning random values racing a window size set is wrong - * should lock here against that + * Locking: tty->termios_mutex is taken to ensure the winsize data + * is consistent. */ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) { - if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) - return -EFAULT; - return 0; + int err; + + mutex_lock(&tty->termios_mutex); + err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); + mutex_unlock(&tty->termios_mutex); + + return err ? -EFAULT: 0; } /** @@ -2773,12 +2779,11 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) * actually has driver level meaning and triggers a VC resize. * * Locking: - * The console_sem is used to ensure we do not try and resize - * the console twice at once. - * FIXME: Two racing size sets may leave the console and kernel - * parameters disagreeing. Is this exploitable ? - * FIXME: Random values racing a window size get is wrong - * should lock here against that + * Called function use the console_sem is used to ensure we do + * not try and resize the console twice at once. + * The tty->termios_mutex is used to ensure we don't double + * resize and get confused. Lock order - tty->termios_mutex before + * console sem */ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, @@ -2788,17 +2793,18 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; + + mutex_lock(&tty->termios_mutex); if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) - return 0; + goto done; + #ifdef CONFIG_VT if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - int rc; - - acquire_console_sem(); - rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); - release_console_sem(); - if (rc) - return -ENXIO; + if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, + tmp_ws.ws_row)) { + mutex_unlock(&tty->termios_mutex); + return -ENXIO; + } } #endif if (tty->pgrp > 0) @@ -2807,6 +2813,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, kill_pg(real_tty->pgrp, SIGWINCH, 1); tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; +done: + mutex_unlock(&tty->termios_mutex); return 0; } @@ -2879,27 +2887,28 @@ static int fionbio(struct file *file, int __user *p) * leader to set this tty as the controlling tty for the session. * * Locking: - * Takes tasklist lock internally to walk sessions - * Takes task_lock() when updating signal->tty - * - * FIXME: tty_mutex is needed to protect signal->tty references. - * FIXME: why task_lock on the signal->tty reference ?? - * + * Takes tty_mutex() to protect tty instance + * Takes tasklist_lock internally to walk sessions + * Takes ->siglock() when updating signal->tty */ static int tiocsctty(struct tty_struct *tty, int arg) { - struct task_struct *p; - + int ret = 0; if (current->signal->leader && (current->signal->session == tty->session)) - return 0; + return ret; + + mutex_lock(&tty_mutex); /* * The process must be a session leader and * not have a controlling tty already. */ - if (!current->signal->leader || current->signal->tty) - return -EPERM; + if (!current->signal->leader || current->signal->tty) { + ret = -EPERM; + goto unlock; + } + if (tty->session > 0) { /* * This tty is already the controlling @@ -2909,22 +2918,18 @@ static int tiocsctty(struct tty_struct *tty, int arg) /* * Steal it away */ - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); + session_clear_tty(tty->session); read_unlock(&tasklist_lock); - } else - return -EPERM; + } else { + ret = -EPERM; + goto unlock; + } } - task_lock(current); - current->signal->tty = tty; - task_unlock(current); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - return 0; + proc_set_tty(current, tty); +unlock: + mutex_unlock(&tty_mutex); + return ret; } /** @@ -2936,7 +2941,7 @@ static int tiocsctty(struct tty_struct *tty, int arg) * Obtain the process group of the tty. If there is no process group * return an error. * - * Locking: none. Reference to ->signal->tty is safe. + * Locking: none. Reference to current->signal->tty is safe. */ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -2963,8 +2968,6 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t * permitted where the tty session is our session. * * Locking: None - * - * FIXME: current->signal->tty referencing is unsafe. */ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -3001,7 +3004,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t * Obtain the session id of the tty. If there is no session * return an error. * - * Locking: none. Reference to ->signal->tty is safe. + * Locking: none. Reference to current->signal->tty is safe. */ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -3045,19 +3048,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) * timed break functionality. * * Locking: - * None + * atomic_write_lock serializes * - * FIXME: - * What if two overlap */ static int send_break(struct tty_struct *tty, unsigned int duration) { + if (mutex_lock_interruptible(&tty->atomic_write_lock)) + return -EINTR; tty->driver->break_ctl(tty, -1); if (!signal_pending(current)) { msleep_interruptible(duration); } tty->driver->break_ctl(tty, 0); + mutex_unlock(&tty->atomic_write_lock); if (signal_pending(current)) return -EINTR; return 0; @@ -3150,6 +3154,8 @@ int tty_ioctl(struct inode * inode, struct file * file, if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; + /* CHECKME: is this safe as one end closes ? */ + real_tty = tty; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -3217,14 +3223,11 @@ int tty_ioctl(struct inode * inode, struct file * file, clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNOTTY: - /* FIXME: taks lock or tty_mutex ? */ if (current->signal->tty != tty) return -ENOTTY; if (current->signal->leader) disassociate_ctty(0); - task_lock(current); - current->signal->tty = NULL; - task_unlock(current); + proc_clear_tty(current); return 0; case TIOCSCTTY: return tiocsctty(tty, arg); @@ -3323,7 +3326,7 @@ static void __do_SAK(void *arg) if (!tty) return; - session = tty->session; + session = tty->session; /* We don't want an ldisc switch during this */ disc = tty_ldisc_ref(tty); @@ -3586,7 +3589,7 @@ static void initialize_tty_struct(struct tty_struct *tty) tty_buffer_init(tty); INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); init_MUTEX(&tty->buf.pty_sem); - init_MUTEX(&tty->termios_sem); + mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 4ad47d321..3b6fa7b0b 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -131,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); @@ -176,7 +177,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios (ld->set_termios)(tty, &old_termios); tty_ldisc_deref(ld); } - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } /** @@ -284,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { struct sgttyb tmp; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tmp.sg_ispeed = 0; tmp.sg_ospeed = 0; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -345,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); return 0; } @@ -422,24 +423,28 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) * * Send a high priority character to the tty even if stopped * - * Locking: none - * - * FIXME: overlapping calls with start/stop tty lose state of tty + * Locking: none for xchar method, write ordering for write method. */ -static void send_prio_char(struct tty_struct *tty, char ch) +static int send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; if (tty->driver->send_xchar) { tty->driver->send_xchar(tty, ch); - return; + return 0; } + + if (mutex_lock_interruptible(&tty->atomic_write_lock)) + return -ERESTARTSYS; + if (was_stopped) start_tty(tty); tty->driver->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); + mutex_unlock(&tty->atomic_write_lock); + return 0; } int n_tty_ioctl(struct tty_struct * tty, struct file * file, @@ -513,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) - send_prio_char(tty, STOP_CHAR(tty)); + return send_prio_char(tty, STOP_CHAR(tty)); break; case TCION: if (START_CHAR(tty) != __DISABLED_CHAR) - send_prio_char(tty, START_CHAR(tty)); + return send_prio_char(tty, START_CHAR(tty)); break; default: return -EINVAL; @@ -592,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return 0; default: return -ENOIOCTLCMD; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index b217da738..4941c9535 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -878,8 +878,17 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) return err; } +int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) +{ + int rc; + + acquire_console_sem(); + rc = vc_resize(vc, cols, lines); + release_console_sem(); + return rc; +} -void vc_disallocate(unsigned int currcons) +void vc_deallocate(unsigned int currcons) { WARN_CONSOLE_UNLOCKED(); @@ -3765,6 +3774,7 @@ EXPORT_SYMBOL(default_blu); EXPORT_SYMBOL(update_region); EXPORT_SYMBOL(redraw_screen); EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(vc_lock_resize); EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(console_blank_hook); EXPORT_SYMBOL(console_blanked); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index a5628a8b6..a53e382cc 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str if (!perm) return -EPERM; if (!i && v == K_NOSUCHMAP) { - /* disallocate map */ + /* deallocate map */ key_map = key_maps[s]; if (s && key_map) { key_maps[s] = NULL; @@ -819,20 +819,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg > MAX_NR_CONSOLES) return -ENXIO; if (arg == 0) { - /* disallocate all unused consoles, but leave 0 */ + /* deallocate all unused consoles, but leave 0 */ acquire_console_sem(); for (i=1; iv_rows) || get_user(cc, &vtsizes->v_cols)) return -EFAULT; - for (i = 0; i < MAX_NR_CONSOLES; i++) { - acquire_console_sem(); - vc_resize(vc_cons[i].d, cc, ll); - release_console_sem(); - } + for (i = 0; i < MAX_NR_CONSOLES; i++) + vc_lock_resize(vc_cons[i].d, cc, ll); return 0; } diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index d10c8b82e..b6f9476c0 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -1907,7 +1907,8 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel) } for (p=buf, count=0; count < len; p++, count++) { - put_user(*card->q931_read++, p); + if (put_user(*card->q931_read++, p)) + return -EFAULT; if (card->q931_read > card->q931_end) card->q931_read = card->q931_buf; } diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index e10350360..9280b581f 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -631,7 +631,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; - copy_to_user(p, cs->status_read, count); + if (copy_to_user(p, cs->status_read, count)) + return -EFAULT; cs->status_read += count; if (cs->status_read > cs->status_end) cs->status_read = cs->status_buf; @@ -642,7 +643,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) cnt = HISAX_STATUS_BUFSIZE; else cnt = count; - copy_to_user(p, cs->status_read, cnt); + if (copy_to_user(p, cs->status_read, cnt)) + return -EFAULT; p += cnt; cs->status_read += cnt % HISAX_STATUS_BUFSIZE; count -= cnt; diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 6649f8bc9..730bbd07e 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1010,7 +1010,8 @@ icn_readstatus(u_char __user *buf, int len, icn_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index fabbd4616..9a66524f1 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -451,7 +451,8 @@ isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card) for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - put_user(*card->msg_buf_read++, p); + if (put_user(*card->msg_buf_read++, p)) + return -EFAULT; if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 94f21486b..6ead5e150 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -725,23 +725,27 @@ static int pcbit_stat(u_char __user *buf, int len, int driver, int channel) if (stat_st < stat_end) { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - copy_to_user(buf, statbuf + stat_st, - STATBUF_LEN - stat_st); - copy_to_user(buf, statbuf, - len - (STATBUF_LEN - stat_st)); + if (copy_to_user(buf, statbuf + stat_st, + STATBUF_LEN - stat_st)) + return -EFAULT; + if (copy_to_user(buf, statbuf, + len - (STATBUF_LEN - stat_st))) + return -EFAULT; stat_st = len - (STATBUF_LEN - stat_st); } else { - copy_to_user(buf, statbuf + stat_st, len); + if (copy_to_user(buf, statbuf + stat_st, len)) + return -EFAULT; stat_st += len; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 98ef9f854..a6dbfef66 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4683,6 +4683,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) if (adapter->hw.phy_type == e1000_phy_igp_3) e1000_phy_powerdown_workaround(&adapter->hw); + if (netif_running(netdev)) + e1000_free_irq(adapter); + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); @@ -4701,6 +4704,7 @@ e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t manc, ret_val; + int err; pci_set_power_state(pdev, PCI_D0); e1000_pci_restore_state(adapter); @@ -4710,6 +4714,10 @@ e1000_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + if (netif_running(netdev) && (err = e1000_request_irq(adapter))) + return err; + + e1000_power_up_phy(adapter); e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 94c38c0c8..38e8bfae4 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4436,6 +4436,50 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); } + +#ifdef CONFIG_PM + +static int nv_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct fe_priv *np = netdev_priv(dev); + + if (!netif_running(dev)) + goto out; + + netif_device_detach(dev); + + // Gross. + nv_close(dev); + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +out: + return 0; +} + +static int nv_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + int rc = 0; + + if (!netif_running(dev)) + goto out; + + netif_device_attach(dev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_enable_wake(pdev, PCI_D0, 0); + + rc = nv_open(dev); +out: + return rc; +} + +#endif /* CONFIG_PM */ + static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), @@ -4537,6 +4581,10 @@ static struct pci_driver driver = { .id_table = pci_tbl, .probe = nv_probe, .remove = __devexit_p(nv_remove), +#ifdef CONFIG_PM + .suspend = nv_suspend, + .resume = nv_resume, +#endif }; diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h index 2024b26b9..63e9fcf31 100644 --- a/drivers/net/wan/pc300.h +++ b/drivers/net/wan/pc300.h @@ -100,6 +100,7 @@ #define _PC300_H #include +#include #include "hd64572.h" #include "pc300-falc-lh.h" diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index ef004d089..d54d5025f 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -425,11 +425,15 @@ fs3270_open(struct inode *inode, struct file *filp) minor = iminor(filp->f_dentry->d_inode); /* Check for minor 0 multiplexer. */ if (minor == 0) { - if (!current->signal->tty) + struct tty_struct *tty; + mutex_lock(&tty_mutex); + tty = get_current_tty(); + if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { + mutex_unlock(&tty_mutex); return -ENODEV; - if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR) - return -ENODEV; - minor = current->signal->tty->index + RAW3270_FIRSTMINOR; + } + minor = tty->index + RAW3270_FIRSTMINOR; + mutex_unlock(&tty_mutex); } /* Check if some other program is already using fullscreen mode. */ fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 29718042c..06e2eeec8 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -698,7 +698,6 @@ tty3270_alloc_view(void) if (!tp->freemem_pages) goto out_tp; INIT_LIST_HEAD(&tp->freemem); - init_timer(&tp->timer); for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { tp->freemem_pages[pages] = (void *) __get_free_pages(GFP_KERNEL|GFP_DMA, 0); diff --git a/fs/buffer.c b/fs/buffer.c index 9f275760f..a61beb1b1 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1181,8 +1181,21 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) } while ((size << sizebits) < PAGE_SIZE); index = block >> sizebits; - block = index << sizebits; + /* + * Check for a block which wants to lie outside our maximum possible + * pagecache index. (this comparison is done using sector_t types). + */ + if (unlikely(index != block >> sizebits)) { + char b[BDEVNAME_SIZE]; + + printk(KERN_ERR "%s: requested out-of-range block %llu for " + "device %s\n", + __FUNCTION__, (unsigned long long)block, + bdevname(bdev, b)); + return -EIO; + } + block = index << sizebits; /* Create a page with the proper size buffers.. */ page = grow_dev_page(bdev, block, index, size); if (!page) @@ -1209,12 +1222,16 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) for (;;) { struct buffer_head * bh; + int ret; bh = __find_get_block(bdev, block, size); if (bh) return bh; - if (!grow_buffers(bdev, block, size)) + ret = grow_buffers(bdev, block, size); + if (ret < 0) + return NULL; + if (ret == 0) free_more_memory(); } } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b88147c1d..36e069f81 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1080,8 +1080,10 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { int err = cifs_revalidate(dentry); - if (!err) + if (!err) { generic_fillattr(dentry->d_inode, stat); + stat->blksize = CIFS_MAX_MSGSIZE; + } return err; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index abc60b781..0e2294c03 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -482,6 +482,8 @@ static int cramfs_readpage(struct file *file, struct page * page) pgdata = kmap(page); if (compr_len == 0) ; /* hole */ + else if (compr_len > (PAGE_CACHE_SIZE << 1)) + printk(KERN_ERR "cramfs: bad compressed blocksize %u\n", compr_len); else { mutex_lock(&read_mutex); bytes_filled = cramfs_uncompress_block(pgdata, diff --git a/fs/dquot.c b/fs/dquot.c index 0122a2791..ad46d2520 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -828,18 +828,23 @@ static inline int need_print_warning(struct dquot *dquot) static void print_warning(struct dquot *dquot, const char warntype) { char *msg = NULL; + struct tty_struct *tty; int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B : ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0); if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) return; - tty_write_message(current->signal->tty, dquot->dq_sb->s_id); + mutex_lock(&tty_mutex); + tty = get_current_tty(); + if (!tty) + goto out_lock; + tty_write_message(tty, dquot->dq_sb->s_id); if (warntype == ISOFTWARN || warntype == BSOFTWARN) - tty_write_message(current->signal->tty, ": warning, "); + tty_write_message(tty, ": warning, "); else - tty_write_message(current->signal->tty, ": write failed, "); - tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]); + tty_write_message(tty, ": write failed, "); + tty_write_message(tty, quotatypes[dquot->dq_type]); switch (warntype) { case IHARDWARN: msg = " file limit reached.\r\n"; @@ -860,7 +865,9 @@ static void print_warning(struct dquot *dquot, const char warntype) msg = " block quota exceeded.\r\n"; break; } - tty_write_message(current->signal->tty, msg); + tty_write_message(tty, msg); +out_lock: + mutex_unlock(&tty_mutex); } static inline void flush_warnings(struct dquot **dquots, char *warntype) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 76ca1cbc3..125d71fc2 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -532,10 +532,12 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) spin_lock(&dreq->lock); - if (likely(status >= 0)) - dreq->count += data->res.count; - else - dreq->error = task->tk_status; + if (unlikely(status < 0)) { + dreq->error = status; + goto out_unlock; + } + + dreq->count += data->res.count; if (data->res.verf->committed != NFS_FILE_SYNC) { switch (dreq->flags) { @@ -550,7 +552,7 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) } } } - +out_unlock: spin_unlock(&dreq->lock); } diff --git a/fs/open.c b/fs/open.c index e866a79eb..bda0a5982 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1214,6 +1214,7 @@ EXPORT_SYMBOL(sys_close); asmlinkage long sys_vhangup(void) { if (capable(CAP_SYS_TTY_CONFIG)) { + /* XXX: this needs locking */ tty_vhangup(current->signal->tty); return 0; } diff --git a/fs/proc/array.c b/fs/proc/array.c index 715194f0a..765cc2994 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -408,6 +408,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) sigemptyset(&sigign); sigemptyset(&sigcatch); cutime = cstime = utime = stime = cputime_zero; + + mutex_lock(&tty_mutex); read_lock(&tasklist_lock); if (task->sighand) { spin_lock_irq(&task->sighand->siglock); @@ -453,6 +455,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) pgid = vx_info_map_pid(task->vx_info, pgid); read_unlock(&tasklist_lock); + mutex_unlock(&tty_mutex); if (!whole || num_threads<2) { wchan = 0; diff --git a/fs/splice.c b/fs/splice.c index 4eed2f6c8..0b8316692 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1041,6 +1041,19 @@ out_release: EXPORT_SYMBOL(do_splice_direct); +/* + * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same + * location, so checking ->i_pipe is not enough to verify that this is a + * pipe. + */ +static inline int is_pipe(struct inode *inode) +{ + if (inode->i_pipe && S_ISFIFO(inode->i_mode)) + return 1; + + return 0; +} + /* * Determine where to splice to/from. */ @@ -1052,8 +1065,8 @@ static long do_splice(struct file *in, loff_t __user *off_in, loff_t offset, *off; long ret; - pipe = in->f_dentry->d_inode->i_pipe; - if (pipe) { + if (is_pipe(in->f_dentry->d_inode)) { + pipe = in->f_dentry->d_inode->i_pipe; if (off_in) return -ESPIPE; if (off_out) { @@ -1073,8 +1086,8 @@ static long do_splice(struct file *in, loff_t __user *off_in, return ret; } - pipe = out->f_dentry->d_inode->i_pipe; - if (pipe) { + if (is_pipe(out->f_dentry->d_inode)) { + pipe = out->f_dentry->d_inode->i_pipe; if (off_out) return -ESPIPE; if (off_in) { @@ -1231,7 +1244,7 @@ static int get_iovec_page_array(const struct iovec __user *iov, static long do_vmsplice(struct file *file, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags) { - struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe; + struct pipe_inode_info *pipe; struct page *pages[PIPE_BUFFERS]; struct partial_page partial[PIPE_BUFFERS]; struct splice_pipe_desc spd = { @@ -1241,7 +1254,7 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov, .ops = &user_page_pipe_buf_ops, }; - if (unlikely(!pipe)) + if (!is_pipe(file->f_dentry->d_inode)) return -EBADF; if (unlikely(nr_segs > UIO_MAXIOV)) return -EINVAL; @@ -1253,6 +1266,7 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov, if (spd.nr_pages <= 0) return spd.nr_pages; + pipe = file->f_dentry->d_inode->i_pipe; return splice_to_pipe(pipe, &spd); } @@ -1475,15 +1489,20 @@ static int link_pipe(struct pipe_inode_info *ipipe, static long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) { - struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; - struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; + struct pipe_inode_info *ipipe; + struct pipe_inode_info *opipe; int ret = -EINVAL; + if (!is_pipe(in->f_dentry->d_inode) || !is_pipe(out->f_dentry->d_inode)) + return ret; + /* * Duplicate the contents of ipipe to opipe without actually * copying the data. */ - if (ipipe && opipe && ipipe != opipe) { + ipipe = in->f_dentry->d_inode->i_pipe; + opipe = out->f_dentry->d_inode->i_pipe; + if (ipipe != opipe) { /* * Keep going, unless we encounter an error. The ipipe/opipe * ordering doesn't really matter. diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 3cadfa5a6..70f88ae70 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -646,7 +646,7 @@ static inline void tracehook_report_clone_complete(unsigned long clone_flags, { #ifdef CONFIG_UTRACE if (current->utrace_flags & UTRACE_ACTION_QUIESCE) - utrace_quiescent(current); + utrace_quiescent(current, NULL); #endif } diff --git a/include/linux/tty.h b/include/linux/tty.h index 04827ca65..35858836f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -174,7 +174,7 @@ struct tty_struct { struct tty_driver *driver; int index; struct tty_ldisc ldisc; - struct semaphore termios_sem; + struct mutex termios_mutex; struct termios *termios, *termios_locked; char name[64]; int pgrp; @@ -190,7 +190,6 @@ struct tty_struct { struct tty_struct *link; struct fasync_struct *fasync; struct tty_bufhead buf; - int max_flip_cnt; int alt_speed; /* For magic substitution of 38400 bps */ wait_queue_head_t write_wait; wait_queue_head_t read_wait; @@ -339,5 +338,45 @@ static inline dev_t tty_devnum(struct tty_struct *tty) return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; } +static inline void proc_clear_tty(struct task_struct *p) +{ + spin_lock_irq(&p->sighand->siglock); + p->signal->tty = NULL; + spin_unlock_irq(&p->sighand->siglock); +} + +static inline +void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +{ + if (tty) { + tty->session = tsk->signal->session; + tty->pgrp = process_group(tsk); + } + tsk->signal->tty = tty; + tsk->signal->tty_old_pgrp = 0; +} + +static inline +void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +{ + spin_lock_irq(&tsk->sighand->siglock); + __proc_set_tty(tsk, tty); + spin_unlock_irq(&tsk->sighand->siglock); +} + +static inline struct tty_struct *get_current_tty(void) +{ + struct tty_struct *tty; + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); + tty = current->signal->tty; + /* + * session->tty can be changed/cleared from under us, make sure we + * issue the load. The obtained pointer, when not NULL, is valid as + * long as we hold tty_mutex. + */ + barrier(); + return tty; +} + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/utrace.h b/include/linux/utrace.h index e0f8ae1cd..f310aa37a 100644 --- a/include/linux/utrace.h +++ b/include/linux/utrace.h @@ -464,7 +464,7 @@ const struct utrace_regset *utrace_regset(struct task_struct *target, /* * Hooks in call these entry points to the utrace dispatch. */ -void utrace_quiescent(struct task_struct *); +int utrace_quiescent(struct task_struct *, struct utrace_signal *); void utrace_release_task(struct task_struct *); int utrace_get_signal(struct task_struct *, struct pt_regs *, siginfo_t *, struct k_sigaction *); diff --git a/include/linux/vs_cvirt.h b/include/linux/vs_cvirt.h index 3158d5a84..c6aa9d3cf 100644 --- a/include/linux/vs_cvirt.h +++ b/include/linux/vs_cvirt.h @@ -146,6 +146,7 @@ struct task_struct *vx_get_proc_task(struct inode *inode, struct pid *pid) "dropping task %p[#%u,%u] for %p[#%u,%u]", task, task->xid, task->pid, current, current->xid, current->pid); + put_task_struct(task); task = NULL; } return task; diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 918a29763..1009d3fe1 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -33,7 +33,8 @@ extern int fg_console, last_console, want_console; int vc_allocate(unsigned int console); int vc_cons_allocated(unsigned int console); int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); -void vc_disallocate(unsigned int console); +int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); +void vc_deallocate(unsigned int console); void reset_palette(struct vc_data *vc); void do_blank_screen(int entering_gfx); void do_unblank_screen(int leaving_gfx); diff --git a/kernel/acct.c b/kernel/acct.c index 2a7c93365..fa54eeb87 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -427,6 +427,7 @@ static void do_acct_process(struct file *file) u64 elapsed; u64 run_time; struct timespec uptime; + struct tty_struct *tty; /* * First check to see if there is enough free_space to continue @@ -483,10 +484,10 @@ static void do_acct_process(struct file *file) ac.ac_ppid = current->parent->tgid; #endif - read_lock(&tasklist_lock); /* pin current->signal */ - ac.ac_tty = current->signal->tty ? - old_encode_dev(tty_devnum(current->signal->tty)) : 0; - read_unlock(&tasklist_lock); + mutex_lock(&tty_mutex); + tty = get_current_tty(); + ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0; + mutex_unlock(&tty_mutex); spin_lock_irq(¤t->sighand->siglock); ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime))); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index c64da575a..8fab061df 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -817,10 +817,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts audit_log_format(ab, " success=%s exit=%ld", (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", context->return_code); + + mutex_lock(&tty_mutex); + read_lock(&tasklist_lock); if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) tty = tsk->signal->tty->name; else tty = "(none)"; + read_unlock(&tasklist_lock); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" " ppid=%d pid=%d auid=%u uid=%u gid=%u" @@ -838,6 +842,9 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts context->gid, context->euid, context->suid, context->fsuid, context->egid, context->sgid, context->fsgid, tty); + + mutex_unlock(&tty_mutex); + audit_log_task_info(ab, tsk); if (context->filterkey) { audit_log_format(ab, " key="); diff --git a/kernel/exit.c b/kernel/exit.c index 99e79125e..80530fbcf 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -385,9 +385,7 @@ void daemonize(const char *name, ...) exit_mm(current); set_special_pids(1, 1); - mutex_lock(&tty_mutex); - current->signal->tty = NULL; - mutex_unlock(&tty_mutex); + proc_clear_tty(current); /* Block and flush all signals */ sigfillset(&blocked); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 786130d1b..ee0b4cb6d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1178,8 +1178,6 @@ ptrace_report(struct utrace_attached_engine *engine, struct task_struct *tsk, } #endif - BUG_ON(state->u.live.stopped); - /* * Set our QUIESCE flag right now, before notifying the tracer. * We do this before setting state->u.live.stopped rather than diff --git a/kernel/sys.c b/kernel/sys.c index ca7ce5228..a87239d9e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1395,7 +1395,6 @@ asmlinkage long sys_setsid(void) pid_t session; int err = -EPERM; - mutex_lock(&tty_mutex); write_lock_irq(&tasklist_lock); /* Fail if I am already a session leader */ @@ -1415,12 +1414,15 @@ asmlinkage long sys_setsid(void) group_leader->signal->leader = 1; __set_special_pids(session, session); + + spin_lock(&group_leader->sighand->siglock); group_leader->signal->tty = NULL; group_leader->signal->tty_old_pgrp = 0; + spin_unlock(&group_leader->sighand->siglock); + err = process_group(group_leader); out: write_unlock_irq(&tasklist_lock); - mutex_unlock(&tty_mutex); return err; } diff --git a/kernel/utrace.c b/kernel/utrace.c index 52d9b0059..5d1e2611a 100644 --- a/kernel/utrace.c +++ b/kernel/utrace.c @@ -119,9 +119,13 @@ utrace_free(struct rcu_head *rhead) kmem_cache_free(utrace_cachep, utrace); } +/* + * Called with utrace locked. Clean it up and free it via RCU. + */ static void rcu_utrace_free(struct utrace *utrace) { + utrace_unlock(utrace); INIT_RCU_HEAD(&utrace->u.dead); call_rcu(&utrace->u.dead, utrace_free); } @@ -135,61 +139,125 @@ utrace_engine_free(struct rcu_head *rhead) } /* - * Called with utrace locked and the target quiescent (maybe current). - * If this was the last engine, utrace is left locked and not freed, - * but is removed from the task. + * Remove the utrace pointer from the task, unless there is a pending + * forced signal (or it's quiescent in utrace_get_signal). */ -static void -remove_engine(struct utrace_attached_engine *engine, - struct task_struct *tsk, struct utrace *utrace) +static inline void +utrace_clear_tsk(struct task_struct *tsk, struct utrace *utrace) { - list_del_rcu(&engine->entry); - if (list_empty(&utrace->engines)) { + if (utrace->u.live.signal == NULL) { task_lock(tsk); if (likely(tsk->utrace != NULL)) { rcu_assign_pointer(tsk->utrace, NULL); - tsk->utrace_flags = 0; + tsk->utrace_flags &= UTRACE_ACTION_NOREAP; } task_unlock(tsk); } - call_rcu(&engine->rhead, utrace_engine_free); } /* - * This is pointed to by the utrace struct, but it's really a private - * structure between utrace_get_signal and utrace_inject_signal. + * Called with utrace locked and the target quiescent (maybe current). + * If this was the last engine and there is no parting forced signal + * pending, utrace is left locked and not freed, but is removed from the task. */ -struct utrace_signal +static void +remove_engine(struct utrace_attached_engine *engine, + struct task_struct *tsk, struct utrace *utrace) { - siginfo_t *const info; - struct k_sigaction *return_ka; - int signr; -}; + list_del_rcu(&engine->entry); + if (list_empty(&utrace->engines)) + utrace_clear_tsk(tsk, utrace); + call_rcu(&engine->rhead, utrace_engine_free); +} + /* * Called with utrace locked, after remove_engine may have run. * Passed the flags from all remaining engines, i.e. zero if none left. * Install the flags in tsk->utrace_flags and return with utrace unlocked. - * If no engines are left, utrace is freed and we return NULL. + * If no engines are left and there is no parting forced signal pending, + * utrace is freed and we return NULL. */ static struct utrace * check_dead_utrace(struct task_struct *tsk, struct utrace *utrace, - unsigned long flags) + unsigned long flags) { - if (flags) { - tsk->utrace_flags = flags; - utrace_unlock(utrace); - return utrace; + long exit_state = 0; + + if (utrace->u.live.signal != NULL) + /* + * There is a pending forced signal. It may have been + * left by an engine now detached. The empty utrace + * remains attached until it can be processed. + */ + flags |= UTRACE_ACTION_QUIESCE; + + /* + * If tracing was preventing a SIGCHLD or self-reaping + * and is no longer, we'll do that report or reaping now. + */ + if (((tsk->utrace_flags &~ flags) & UTRACE_ACTION_NOREAP) + && tsk->exit_state && !utrace->u.exit.notified) { + BUG_ON(tsk->exit_state != EXIT_ZOMBIE); + /* + * While holding the utrace lock, mark that it's been done. + * For self-reaping, we need to change tsk->exit_state + * before clearing tsk->utrace_flags, so that the real + * parent can't see it in EXIT_ZOMBIE momentarily and reap it. + */ + utrace->u.exit.notified = 1; + if (tsk->exit_signal == -1) { + exit_state = xchg(&tsk->exit_state, EXIT_DEAD); + BUG_ON(exit_state != EXIT_ZOMBIE); + exit_state = EXIT_DEAD; + + /* + * Now that we've changed its state to DEAD, + * it's safe to install the new tsk->utrace_flags + * value without the UTRACE_ACTION_NOREAP bit set. + */ + } + else if (thread_group_empty(tsk)) { + /* + * We need to prevent the real parent from reaping + * until after we've called do_notify_parent, below. + * It can get into wait_task_zombie any time after + * the UTRACE_ACTION_NOREAP bit is cleared. It's + * safe for that to do everything it does until its + * release_task call starts tearing things down. + * Holding tasklist_lock for reading prevents + * release_task from proceeding until we've done + * everything we need to do. + */ + exit_state = EXIT_ZOMBIE; + read_lock(&tasklist_lock); + } } - if (utrace->u.live.signal && utrace->u.live.signal->signr != 0) { + tsk->utrace_flags = flags; + if (flags) utrace_unlock(utrace); - return utrace; + else { + rcu_utrace_free(utrace); + utrace = NULL; } - utrace_unlock(utrace); - rcu_utrace_free(utrace); - return NULL; + /* + * Now we're finished updating the utrace state. + * Do a pending self-reaping or parent notification. + */ + if (exit_state == EXIT_DEAD) + /* + * Note this can wind up in utrace_reap and do more callbacks. + * Our callers must be in places where that is OK. + */ + release_task(tsk); + else if (exit_state == EXIT_ZOMBIE) { + do_notify_parent(tsk, tsk->exit_signal); + read_unlock(&tasklist_lock); /* See comment above. */ + } + + return utrace; } @@ -299,6 +367,7 @@ restart: rcu_read_unlock(); return engine; } + rcu_read_unlock(); engine = kmem_cache_alloc(utrace_engine_cachep, SLAB_KERNEL); if (unlikely(engine == NULL)) @@ -311,8 +380,8 @@ restart: rcu_read_unlock(); goto first; } - utrace_lock(utrace); + if (flags & UTRACE_ATTACH_EXCLUSIVE) { struct utrace_attached_engine *old; old = matching_engine(utrace, flags, ops, data); @@ -334,6 +403,8 @@ restart: kmem_cache_free(utrace_engine_cachep, engine); goto restart; } + rcu_read_unlock(); + list_add_tail_rcu(&engine->entry, &utrace->engines); } @@ -365,29 +436,6 @@ static const struct utrace_engine_ops dead_engine_ops = }; -/* - * If tracing was preventing a SIGCHLD or self-reaping - * and is no longer, do that report or reaping right now. - */ -static void -check_noreap(struct task_struct *target, struct utrace *utrace, - u32 old_action, u32 action) -{ - if ((action | ~old_action) & UTRACE_ACTION_NOREAP) - return; - - if (utrace && xchg(&utrace->u.exit.notified, 1)) - return; - - if (target->exit_signal == -1) - release_task(target); - else if (thread_group_empty(target)) { - read_lock(&tasklist_lock); - do_notify_parent(target, target->exit_signal); - read_unlock(&tasklist_lock); - } -} - /* * We may have been the one keeping the target thread quiescent. * Check if it should wake up now. @@ -411,8 +459,6 @@ wake_quiescent(unsigned long old_flags, list_for_each_entry(engine, &utrace->engines, entry) flags |= engine->flags | UTRACE_EVENT(REAP); utrace = check_dead_utrace(target, utrace, flags); - - check_noreap(target, utrace, old_flags, flags); return; } @@ -528,7 +574,6 @@ restart: } call_rcu(&engine->rhead, utrace_engine_free); } - utrace_unlock(utrace); rcu_utrace_free(utrace); } @@ -694,9 +739,8 @@ remove_detached(struct task_struct *tsk, struct utrace *utrace, struct utrace **utracep, u32 action) { struct utrace_attached_engine *engine, *next; - unsigned long flags; + unsigned long flags = 0; - flags = 0; list_for_each_entry_safe(engine, next, &utrace->engines, entry) { if (engine->ops == &dead_engine_ops) remove_engine(engine, tsk, utrace); @@ -724,11 +768,12 @@ check_detach(struct task_struct *tsk, u32 action) return action; } -static inline void +static inline int check_quiescent(struct task_struct *tsk, u32 action) { if (action & UTRACE_ACTION_STATE_MASK) - utrace_quiescent(tsk); + return utrace_quiescent(tsk, NULL); + return 0; } /* @@ -826,13 +871,31 @@ utrace_report_jctl(int what) } +/* + * Return nonzero if there is a SIGKILL that should be waking us up. + * Called with the siglock held. + */ +static inline int +sigkill_pending(struct task_struct *tsk) +{ + return ((sigismember(&tsk->pending.signal, SIGKILL) + || sigismember(&tsk->signal->shared_pending.signal, SIGKILL)) + && !unlikely(sigismember(&tsk->blocked, SIGKILL))); +} + /* * Called if UTRACE_EVENT(QUIESCE) or UTRACE_ACTION_QUIESCE flag is set. * Also called after other event reports. * It is a good time to block. + * Returns nonzero if we woke up prematurely due to SIGKILL. + * + * The signal pointer is nonzero when called from utrace_get_signal, + * where a pending forced signal can be processed right away. Otherwise, + * we keep UTRACE_ACTION_QUIESCE set after resuming so that utrace_get_signal + * will be entered before user mode. */ -void -utrace_quiescent(struct task_struct *tsk) +int +utrace_quiescent(struct task_struct *tsk, struct utrace_signal *signal) { struct utrace *utrace = tsk->utrace; unsigned long action; @@ -846,6 +909,13 @@ restart: * If some engines want us quiescent, we block here. */ if (action & UTRACE_ACTION_QUIESCE) { + int killed; + + if (signal != NULL) { + BUG_ON(utrace->u.live.signal != NULL); + utrace->u.live.signal = signal; + } + spin_lock_irq(&tsk->sighand->siglock); /* * If wake_quiescent is trying to wake us up now, it will @@ -855,8 +925,8 @@ restart: * release the siglock it's waiting for. * Never stop when there is a SIGKILL bringing us down. */ - if ((tsk->utrace_flags & UTRACE_ACTION_QUIESCE) - /*&& !(tsk->signal->flags & SIGNAL_GROUP_SIGKILL)*/) { + killed = sigkill_pending(tsk); + if (!killed && (tsk->utrace_flags & UTRACE_ACTION_QUIESCE)) { set_current_state(TASK_TRACED); /* * If there is a group stop in progress, @@ -870,6 +940,20 @@ restart: else spin_unlock_irq(&tsk->sighand->siglock); + if (signal != NULL) { + /* + * We know the struct stays in place when its + * u.live.signal is set, see check_dead_utrace. + * This makes it safe to clear its pointer here. + */ + BUG_ON(tsk->utrace != utrace); + BUG_ON(utrace->u.live.signal != signal); + utrace->u.live.signal = NULL; + } + + if (killed) /* Game over, man! */ + return 1; + /* * We've woken up. One engine could be waking us up while * another has asked us to quiesce. So check afresh. We @@ -887,6 +971,10 @@ restart: * Our flags are out of date. * Update the set of events of interest from the union * of the interests of the remaining tracing engines. + * This may notice that there are no engines left + * and clean up the struct utrace. It's left in place + * and the QUIESCE flag set as long as utrace_get_signal + * still needs to process a pending forced signal. */ struct utrace_attached_engine *engine; unsigned long flags = 0; @@ -894,8 +982,9 @@ restart: utrace_lock(utrace); list_for_each_entry(engine, &utrace->engines, entry) flags |= engine->flags | UTRACE_EVENT(REAP); - tsk->utrace_flags = flags; - utrace_unlock(utrace); + if (flags == 0) + utrace_clear_tsk(tsk, utrace); + utrace = check_dead_utrace(tsk, utrace, flags); } /* @@ -918,6 +1007,8 @@ restart: tracehook_enable_syscall_trace(tsk); else tracehook_disable_syscall_trace(tsk); + + return 0; } @@ -946,7 +1037,7 @@ utrace_report_exit(long *exit_code) } /* - * Called iff UTRACE_EVENT(DEATH) flag is set. + * Called iff UTRACE_EVENT(DEATH) or UTRACE_ACTION_QUIESCE flag is set. * * It is always possible that we are racing with utrace_release_task here, * if UTRACE_ACTION_NOREAP is not set, or in the case of non-leader exec @@ -974,6 +1065,7 @@ utrace_report_death(struct task_struct *tsk, struct utrace *utrace) if (engine->flags & UTRACE_EVENT(QUIESCE)) REPORT(report_quiesce); } + /* * Unconditionally lock and recompute the flags. * This may notice that there are no engines left and @@ -1006,8 +1098,6 @@ utrace_report_death(struct task_struct *tsk, struct utrace *utrace) utrace_unlock(utrace); } - - check_noreap(tsk, utrace, oaction, action); } } @@ -1095,9 +1185,27 @@ utrace_report_syscall(struct pt_regs *regs, int is_exit) break; } action = check_detach(tsk, action); - check_quiescent(tsk, action); + if (unlikely(check_quiescent(tsk, action)) && !is_exit) + /* + * We are continuing despite QUIESCE because of a SIGKILL. + * Don't let the system call actually proceed. + */ + tracehook_abort_syscall(regs); } + +/* + * This is pointed to by the utrace struct, but it's really a private + * structure between utrace_get_signal and utrace_inject_signal. + */ +struct utrace_signal +{ + siginfo_t *const info; + struct k_sigaction *return_ka; + int signr; +}; + + // XXX copied from signal.c #ifdef SIGEMT #define M_SIGEMT M(SIGEMT) @@ -1191,38 +1299,15 @@ utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs, struct k_sigaction *ka; unsigned long action, event; -#if 0 /* XXX */ - if (tsk->signal->flags & SIGNAL_GROUP_SIGKILL) - return 0; -#endif - - /* - * If we should quiesce, now is the time. - * First stash a pointer to the state on our stack, - * so that utrace_inject_signal can tell us what to do. - */ - if (utrace->u.live.signal == NULL) - utrace->u.live.signal = &signal; - - if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) { - spin_unlock_irq(&tsk->sighand->siglock); - utrace_quiescent(tsk); - if (signal.signr == 0) - /* - * This return value says to reacquire the siglock - * and check again. This will check for a pending - * group stop and process it before coming back here. - */ - return -1; - spin_lock_irq(&tsk->sighand->siglock); - } - /* * If a signal was injected previously, it could not use our * stack space directly. It had to allocate a data structure, * which we can now copy out of and free. + * + * We don't have to lock access to u.live.signal because it's only + * touched by utrace_inject_signal when we're quiescent. */ - if (utrace->u.live.signal != &signal) { + if (utrace->u.live.signal != NULL) { signal.signr = utrace->u.live.signal->signr; copy_siginfo(info, utrace->u.live.signal->info); if (utrace->u.live.signal->return_ka) @@ -1230,8 +1315,57 @@ utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs, else signal.return_ka = NULL; kfree(utrace->u.live.signal); + utrace->u.live.signal = NULL; + } + + /* + * If we should quiesce, now is the time. + * First stash a pointer to the state on our stack, + * so that utrace_inject_signal can tell us what to do. + */ + if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) { + int killed = sigkill_pending(tsk); + if (!killed) { + spin_unlock_irq(&tsk->sighand->siglock); + + killed = utrace_quiescent(tsk, &signal); + + /* + * Noone wants us quiescent any more, we can take + * signals. Unless we have a forced signal to take, + * back out to the signal code to resynchronize after + * releasing the siglock. + */ + if (signal.signr == 0 && !killed) + /* + * This return value says to reacquire the + * siglock and check again. This will check + * for a pending group stop and process it + * before coming back here. + */ + return -1; + + spin_lock_irq(&tsk->sighand->siglock); + } + if (killed) { + /* + * The only reason we woke up now was because of a + * SIGKILL. Don't do normal dequeuing in case it + * might get a signal other than SIGKILL. That would + * perturb the death state so it might differ from + * what the debugger would have allowed to happen. + * Instead, pluck out just the SIGKILL to be sure + * we'll die immediately with nothing else different + * from the quiescent state the debugger wanted us in. + */ + sigset_t sigkill_only; + sigfillset(&sigkill_only); + sigdelset(&sigkill_only, SIGKILL); + killed = dequeue_signal(tsk, &sigkill_only, info); + BUG_ON(killed != SIGKILL); + return killed; + } } - utrace->u.live.signal = NULL; /* * If a signal was injected, everything is in place now. Go do it. @@ -1270,6 +1404,10 @@ utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs, ka = &tsk->sighand->action[signal.signr - 1]; *return_ka = *ka; + /* + * We are never allowed to interfere with SIGKILL, + * just punt after filling in *return_ka for our caller. + */ if (signal.signr == SIGKILL) return signal.signr; @@ -1329,9 +1467,6 @@ utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs, recalc_sigpending_tsk(tsk); } - if (tsk->utrace != utrace) - rcu_utrace_free(utrace); - /* * We express the chosen action to the signals code in terms * of a representative signal whose default action does it. @@ -1416,7 +1551,9 @@ utrace_inject_signal(struct task_struct *target, ret = 0; signal = utrace->u.live.signal; - if (signal == NULL) { + if (unlikely(target->exit_state)) + ret = -ESRCH; + else if (signal == NULL) { ret = -ENOSYS; /* XXX */ } else if (signal->signr != 0) diff --git a/mm/migrate.c b/mm/migrate.c index 08c9fff40..e85c60a9c 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -950,7 +950,8 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, goto out; pm[i].node = node; - } + } else + pm[i].node = 0; /* anything to not match MAX_NUMNODES */ } /* End marker */ pm[nr_pages].node = MAX_NUMNODES; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4d6ba97d4..fc515fe86 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1705,10 +1705,13 @@ static inline void flush_unauthorized_files(struct files_struct * files) { struct avc_audit_data ad; struct file *file, *devnull = NULL; - struct tty_struct *tty = current->signal->tty; + struct tty_struct *tty; struct fdtable *fdt; long j = -1; + int drop_tty = 0; + mutex_lock(&tty_mutex); + tty = get_current_tty(); if (tty) { file_list_lock(); file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list); @@ -1721,13 +1724,16 @@ static inline void flush_unauthorized_files(struct files_struct * files) struct inode *inode = file->f_dentry->d_inode; if (inode_has_perm(current, inode, FILE__READ | FILE__WRITE, NULL)) { - /* Reset controlling tty. */ - current->signal->tty = NULL; - current->signal->tty_old_pgrp = 0; + drop_tty = 1; } } file_list_unlock(); + + /* Reset controlling tty. */ + if (drop_tty) + proc_set_tty(current, NULL); } + mutex_unlock(&tty_mutex); /* Revalidate access to inherited open files. */ -- 2.43.0