Here it is again against 2.5.18.
This patch moves a version of copy_siginfo_to_user that is common to
ten of our architectures into the gerneic code and allows the other
architectures to override it. I suspect more of the remaining
architectures will be able to use it as well once it is fixed (patch
to follow).
Please apply.
-- Cheers, Stephen Rothwell sfr@canb.auug.org.au http://www.canb.auug.org.au/~sfr/diff -ruN 2.5.18/arch/arm/kernel/signal.c 2.5.18-si.4/arch/arm/kernel/signal.c --- 2.5.18/arch/arm/kernel/signal.c Sun May 26 19:20:19 2002 +++ 2.5.18-si.4/arch/arm/kernel/signal.c Mon May 27 00:39:15 2002 @@ -51,42 +51,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - int err = -EFAULT;; - - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - goto out; - - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } -out: - return err; -} - /* * atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/i386/kernel/signal.c 2.5.18-si.4/arch/i386/kernel/signal.c --- 2.5.18/arch/i386/kernel/signal.c Sun May 26 19:20:20 2002 +++ 2.5.18-si.4/arch/i386/kernel/signal.c Mon May 27 00:39:15 2002 @@ -30,41 +30,6 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/m68k/kernel/signal.c 2.5.18-si.4/arch/m68k/kernel/signal.c --- 2.5.18/arch/m68k/kernel/signal.c Fri May 10 09:35:06 2002 +++ 2.5.18-si.4/arch/m68k/kernel/signal.c Mon May 27 00:39:15 2002 @@ -190,41 +190,6 @@ }; -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ static inline int restore_fpu_state(struct sigcontext *sc) diff -ruN 2.5.18/arch/mips/kernel/signal.c 2.5.18-si.4/arch/mips/kernel/signal.c --- 2.5.18/arch/mips/kernel/signal.c Mon Apr 15 10:44:54 2002 +++ 2.5.18-si.4/arch/mips/kernel/signal.c Mon May 27 00:39:15 2002 @@ -37,41 +37,6 @@ extern asmlinkage void syscall_trace(void); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/ppc/kernel/signal.c 2.5.18-si.4/arch/ppc/kernel/signal.c --- 2.5.18/arch/ppc/kernel/signal.c Fri May 10 09:35:08 2002 +++ 2.5.18-si.4/arch/ppc/kernel/signal.c Mon May 27 00:39:15 2002 @@ -62,41 +62,6 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/ppc64/kernel/signal.c 2.5.18-si.4/arch/ppc64/kernel/signal.c --- 2.5.18/arch/ppc64/kernel/signal.c Fri May 3 12:08:04 2002 +++ 2.5.18-si.4/arch/ppc64/kernel/signal.c Mon May 27 00:39:15 2002 @@ -65,41 +65,6 @@ extern long sys_wait4(pid_t pid, unsigned int *stat_addr, int options, /*unsigned long*/ struct rusage *ru); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/s390/kernel/signal.c 2.5.18-si.4/arch/s390/kernel/signal.c --- 2.5.18/arch/s390/kernel/signal.c Wed Feb 20 16:36:40 2002 +++ 2.5.18-si.4/arch/s390/kernel/signal.c Mon May 27 00:39:15 2002 @@ -49,41 +49,6 @@ asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/s390x/kernel/signal.c 2.5.18-si.4/arch/s390x/kernel/signal.c --- 2.5.18/arch/s390x/kernel/signal.c Wed Feb 20 16:36:40 2002 +++ 2.5.18-si.4/arch/s390x/kernel/signal.c Mon May 27 00:39:15 2002 @@ -49,41 +49,6 @@ asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/sh/kernel/signal.c 2.5.18-si.4/arch/sh/kernel/signal.c --- 2.5.18/arch/sh/kernel/signal.c Wed Feb 20 16:36:40 2002 +++ 2.5.18-si.4/arch/sh/kernel/signal.c Mon May 27 00:39:15 2002 @@ -34,41 +34,6 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -ruN 2.5.18/arch/x86_64/kernel/signal.c 2.5.18-si.4/arch/x86_64/kernel/signal.c --- 2.5.18/arch/x86_64/kernel/signal.c Tue Apr 23 10:42:14 2002 +++ 2.5.18-si.4/arch/x86_64/kernel/signal.c Mon May 27 00:39:15 2002 @@ -39,41 +39,6 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs); -int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{ - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; - } -} - asmlinkage long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs regs) { diff -ruN 2.5.18/include/asm-alpha/siginfo.h 2.5.18-si.4/include/asm-alpha/siginfo.h --- 2.5.18/include/asm-alpha/siginfo.h Tue Apr 23 10:42:28 2002 +++ 2.5.18-si.4/include/asm-alpha/siginfo.h Mon May 27 00:39:15 2002 @@ -227,6 +227,7 @@ memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -ruN 2.5.18/include/asm-cris/siginfo.h 2.5.18-si.4/include/asm-cris/siginfo.h --- 2.5.18/include/asm-cris/siginfo.h Mon Feb 11 17:37:27 2002 +++ 2.5.18-si.4/include/asm-cris/siginfo.h Mon May 27 00:39:15 2002 @@ -226,6 +226,7 @@ memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -ruN 2.5.18/include/asm-ia64/siginfo.h 2.5.18-si.4/include/asm-ia64/siginfo.h --- 2.5.18/include/asm-ia64/siginfo.h Mon Apr 29 14:57:13 2002 +++ 2.5.18-si.4/include/asm-ia64/siginfo.h Mon May 27 00:39:15 2002 @@ -271,6 +271,7 @@ memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); diff -ruN 2.5.18/include/asm-mips64/siginfo.h 2.5.18-si.4/include/asm-mips64/siginfo.h --- 2.5.18/include/asm-mips64/siginfo.h Mon Feb 11 17:37:27 2002 +++ 2.5.18-si.4/include/asm-mips64/siginfo.h Mon May 27 00:39:15 2002 @@ -248,6 +248,7 @@ memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -ruN 2.5.18/include/asm-parisc/siginfo.h 2.5.18-si.4/include/asm-parisc/siginfo.h --- 2.5.18/include/asm-parisc/siginfo.h Mon Feb 11 17:37:27 2002 +++ 2.5.18-si.4/include/asm-parisc/siginfo.h Mon May 27 00:39:15 2002 @@ -228,6 +228,7 @@ memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -ruN 2.5.18/include/asm-sparc/siginfo.h 2.5.18-si.4/include/asm-sparc/siginfo.h --- 2.5.18/include/asm-sparc/siginfo.h Tue Mar 19 15:12:09 2002 +++ 2.5.18-si.4/include/asm-sparc/siginfo.h Mon May 27 00:39:15 2002 @@ -236,6 +236,7 @@ memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); #endif /* __KERNEL__ */ diff -ruN 2.5.18/include/asm-sparc64/siginfo.h 2.5.18-si.4/include/asm-sparc64/siginfo.h --- 2.5.18/include/asm-sparc64/siginfo.h Tue Mar 19 15:12:09 2002 +++ 2.5.18-si.4/include/asm-sparc64/siginfo.h Mon May 27 00:39:15 2002 @@ -311,6 +311,7 @@ memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } +#define HAVE_ARCH_COPY_SIGINFO_TO_USER extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); extern int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from); diff -ruN 2.5.18/kernel/signal.c 2.5.18-si.4/kernel/signal.c --- 2.5.18/kernel/signal.c Sun May 26 19:20:36 2002 +++ 2.5.18-si.4/kernel/signal.c Mon May 27 00:39:15 2002 @@ -16,6 +16,7 @@ #include <linux/fs.h> #include <asm/uaccess.h> +#include <asm/siginfo.h> /* * SLAB caches for signal bits. @@ -931,6 +932,45 @@ { return do_sigpending(set, sigsetsize); } + +#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER + +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + +#endif asmlinkage long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/