git-pull request for tip/cpus4096
Hi Ingo,
Here's the latest cpumask updates which includes the latest merge from Rusty's cpumask tree.
Thanks,
Mike
The following changes since commit 2ca1a615835d9f4990f42102ab1f2ef434e7e89c:
Rusty Russell (1):
Merge branch 'master' of git://git.kernel.org/.../torvalds/linux-2.6
are available in the git repository at:
ssh://master.kernel.org/pub/scm/linux/kernel/git/travis/linux-2.6-cpus4096-for-ingo.git master
Gautham R Shenoy (1):
sched: framework for sched_mc/smt_power_savings=N
Ingo Molnar (19):
Merge branches 'sched/core', 'core/core' and 'tracing/core' into cpus4096
sched: convert struct root_domain to cpumask_var_t, fix
Merge branch 'linus' into cpus4096
Merge branch 'tracing/fastboot' into cpus4096
Merge branch 'sched/core' into cpus4096
Merge branches 'irq/sparseirq', 'x86/quirks' and 'x86/reboot' into cpus4096
Merge branch 'linus' into cpus4096
Merge branch 'master' of git://git.kernel.org/.../rusty/linux-2.6-for-ingo into cpus4096 Merge branch 'linus' into cpus4096
Merge branch 'master' of git://git.kernel.org/.../travis/linux-2.6-cpus4096-for-ingo into cpus4096 Merge branch 'irq/sparseirq' into cpus4096
Merge branch 'x86/crashdump' into cpus4096
x86: update io_apic.c to the new cpumask code
Merge branch 'linus' into cpus4096
Merge branch 'x86/apic' into cpus4096
sched: move test_sd_parent() to an SMP section of sched.h
sched: fix warning in kernel/sched.c
x86: fix warning in arch/x86/kernel/io_apic.c
x86: export vector_used_by_percpu_irq
Li Zefan (1):
cpumask: fix bogus kernel-doc
Mike Travis (29):
sched: reduce stack size requirements in kernel/sched.c
x86: fix build error with post-merge of tip/cpus4096 and rr-for-ingo/master.
x86: enable MAXSMP
x86 smp: modify send_IPI_mask interface to accept cpumask_t pointers
x86: move and enhance debug printk for nr_cpu_ids etc.
x86: Add cpu_mask_to_apicid_and
x86: update add-cpu_mask_to_apicid_and to use struct cpumask*
x86: Update io_apic.c to use new cpumask API
xen: convert to cpumask_var_t and new cpumask primitives.
x86: fixup_irqs() doesnt need an argument.
x86: cosmetic changes apic-related files.
x86: Set CONFIG_NR_CPUS even on UP
x86: prepare for cpumask iterators to only go to nr_cpu_ids
x86: Use cpumask accessors code for possible/present maps.
x86: Remove cpumask games in x86/kernel/cpu/intel_cacheinfo.c
x86: use work_on_cpu in x86/kernel/cpu/mcheck/mce_amd_64.c
x86: xen: use smp_call_function_many()
x86: Introduce topology_core_cpumask()/topology_thread_cpumask()
x86: fix cpu_mask_to_apicid_and to include cpu_online_mask
x86: use possible_cpus=NUM to extend the possible cpus allowed
Merge branch 'master' of git://git.kernel.org/.../rusty/linux-2.6-cpumask into merge-rr-cpumask
x86: enable cpus display of kernel_max and offlined cpus
x86: cleanup remaining cpumask_t ops in smpboot code
sched: put back some stack hog changes that were undone in kernel/sched.c
x86: cleanup some remaining usages of NR_CPUS where s/b nr_cpu_ids
x86: cleanup remaining cpumask_t code in mce_amd_64.c
x86: cleanup remaining cpumask_t code in microcode_core.c
cpumask: use alloc_cpumask_var_node where appropriate
cpumask: fix compile error when CONFIG_NR_CPUS is not defined
Rusty Russell (58):
sched: convert sched.c from for_each_cpu_mask to for_each_cpu.
sched: get rid of boutique sched.c allocations, use cpumask_var_t.
sched: remove any_online_cpu()
sched: wrap sched_group and sched_domain cpumask accesses.
sched: convert struct sched_group/sched_domain cpumask_ts to variable bitmaps
sched: convert nohz_cpu_mask to cpumask_var_t.
sched: convert struct root_domain to cpumask_var_t.
sched: convert nohz struct to cpumask_var_t.
sched: convert idle_balance() to cpumask_var_t.
sched: convert rebalance_domains() to cpumask_var_t.
sched: convert sys_sched_getaffinity() to cpumask_var_t.
sched: avoid stack var in move_task_off_dead_cpu
sched: convert struct (sys_)sched_setaffinity() to cpumask_var_t.
sched: convert sched_domain_debug to cpumask_var_t.
sched: convert cpu_isolated_map to cpumask_var_t.
sched: convert falback_doms to cpumask_var_t.
sched: convert struct cpupri_vec cpumask_var_t.
sched: convert check_preempt_equal_prio to cpumask_var_t.
sched: convert local_cpu_mask to cpumask_var_t.
sched: convert remaining old-style cpumask operators
sched: convert nohz struct to cpumask_var_t, fix
sched: convert local_cpu_mask to cpumask_var_t, fix
sched: avoid stack var in move_task_off_dead_cpu, fix
Merge ../linux-2.6-x86
cpumask: Remove IA64 definition of total_cpus now it's in core code
percpu: fix percpu accessors to potentially !cpu_possible() cpus: pnpbios
percpu: fix percpu accessors to potentially !cpu_possible() cpus: m32r
cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits.: core
cpumask: Use accessors code in core
parisc: remove gratuitous cpu_online_map declaration.
avr32: define __fls
blackfin: define __fls
m68k: define __fls
m68knommu: define __fls
bitmap: find_last_bit()
cpumask: Use find_last_bit()
cpumask: Introduce topology_core_cpumask()/topology_thread_cpumask(): sparc
cpumask: Introduce topology_core_cpumask()/topology_thread_cpumask(): s390
cpumask: Introduce topology_core_cpumask()/topology_thread_cpumask(): powerpc
cpumask: Introduce topology_core_cpumask()/topology_thread_cpumask(): ia64
cpumask: convert kernel trace functions
cpumask: convert kernel trace functions further
cpumask: remove any_online_cpu() users: kernel/
cpumask: remove any_online_cpu() users: mm/
cpumask: convert kernel/compat.c
cpumask: convert kernel/workqueue.c
cpumask: convert kernel time functions
cpumask: convert kernel/irq
cpumask: convert RCU implementations
cpumask: convert kernel/profile.c
cpumask: convert kernel/cpu.c
cpumask: convert rest of files in kernel/
cpumask: convert mm/
cpumask: replace for_each_cpu_mask_nr with for_each_cpu in kernel/time/
cpumask: zero extra bits in alloc_cpumask_var_node
cpumask: CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
x86: use cpumask_var_t in acpi/boot.c
cpumask: convert shared_cpu_map in acpi_processor* structs to cpumask_var_t
Sergio Luis (1):
x86: mark get_cpu_leaves() with __cpuinit annotation
Suresh Siddha (1):
x86: use logical apicid in x2apic_cluster's x2apic_cpu_mask_to_apicid_and()
Vaidyanathan Srinivasan (7):
sched: convert BALANCE_FOR_xx_POWER to inline functions
sched: favour lower logical cpu number for sched_mc balance
sched: nominate preferred wakeup cpu
sched: bias task wakeups to preferred semi-idle packages
sched: activate active load balancing in new idle cpus
sched: add SD_BALANCE_NEWIDLE at MC and CPU level for sched_mc>0
sched: nominate preferred wakeup cpu, fix
Yinghai Lu (1):
x86: fix lguest used_vectors breakage, -v2
Documentation/cpu-hotplug.txt | 17 +- arch/alpha/kernel/irq.c | 3 +- arch/avr32/include/asm/bitops.h | 5 + arch/blackfin/include/asm/bitops.h | 1 + arch/ia64/include/asm/topology.h | 4 +- arch/ia64/kernel/acpi.c | 1 - arch/m32r/kernel/smpboot.c | 2 +- arch/m68knommu/include/asm/bitops.h | 1 + arch/mips/include/asm/mach-ip27/topology.h | 1 - arch/parisc/include/asm/smp.h | 2 - arch/powerpc/include/asm/topology.h | 3 +- arch/s390/include/asm/topology.h | 1 + arch/sh/include/asm/topology.h | 1 - arch/sparc/include/asm/topology_64.h | 2 + arch/x86/Kconfig | 13 +- arch/x86/include/asm/bigsmp/apic.h | 32 +- arch/x86/include/asm/bigsmp/ipi.h | 13 +- arch/x86/include/asm/desc.h | 10 +- arch/x86/include/asm/es7000/apic.h | 60 +- arch/x86/include/asm/es7000/ipi.h | 12 +- arch/x86/include/asm/genapic_32.h | 13 +- arch/x86/include/asm/genapic_64.h | 14 +- arch/x86/include/asm/ipi.h | 23 +- arch/x86/include/asm/irq.h | 3 +- arch/x86/include/asm/lguest.h | 2 +- arch/x86/include/asm/mach-default/mach_apic.h | 28 +- arch/x86/include/asm/mach-default/mach_ipi.h | 18 +- arch/x86/include/asm/mach-generic/mach_apic.h | 1 + arch/x86/include/asm/numaq/apic.h | 16 +- arch/x86/include/asm/numaq/ipi.h | 13 +- arch/x86/include/asm/smp.h | 38 +- arch/x86/include/asm/summit/apic.h | 39 +- arch/x86/include/asm/summit/ipi.h | 9 +- arch/x86/include/asm/topology.h | 2 + arch/x86/kernel/acpi/boot.c | 31 +- arch/x86/kernel/apic.c | 30 +- arch/x86/kernel/cpu/common.c | 28 +- arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 28 +- arch/x86/kernel/cpu/cpufreq/powernow-k7.c | 9 + arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 24 +- arch/x86/kernel/cpu/intel_cacheinfo.c | 41 +- arch/x86/kernel/cpu/mcheck/mce_amd_64.c | 131 ++-- arch/x86/kernel/cpuid.c | 2 +- arch/x86/kernel/genapic_flat_64.c | 107 ++- arch/x86/kernel/genx2apic_cluster.c | 81 ++- arch/x86/kernel/genx2apic_phys.c | 74 ++- arch/x86/kernel/genx2apic_uv_x.c | 61 ++- arch/x86/kernel/io_apic.c | 358 +++++----- arch/x86/kernel/ipi.c | 28 +- arch/x86/kernel/irq.c | 3 + arch/x86/kernel/irq_32.c | 13 +- arch/x86/kernel/irq_64.c | 15 +- arch/x86/kernel/irqinit_32.c | 16 +- arch/x86/kernel/irqinit_64.c | 13 + arch/x86/kernel/microcode_core.c | 83 ++- arch/x86/kernel/msr.c | 2 +- arch/x86/kernel/reboot.c | 9 +- arch/x86/kernel/setup_percpu.c | 42 +- arch/x86/kernel/smp.c | 23 +- arch/x86/kernel/smpboot.c | 159 +++-- arch/x86/kernel/tlb_32.c | 2 +- arch/x86/kernel/tlb_64.c | 2 +- arch/x86/kernel/traps.c | 12 +- arch/x86/mach-generic/bigsmp.c | 5 +- arch/x86/mach-generic/es7000.c | 5 +- arch/x86/mach-generic/numaq.c | 5 +- arch/x86/mach-generic/summit.c | 5 +- arch/x86/mach-voyager/voyager_smp.c | 9 +- arch/x86/mm/numa_64.c | 4 +- arch/x86/mm/srat_64.c | 2 +- arch/x86/xen/mmu.c | 20 +- arch/x86/xen/smp.c | 27 +- arch/x86/xen/suspend.c | 3 +- arch/x86/xen/xen-ops.h | 2 +- drivers/acpi/processor_core.c | 14 +- drivers/acpi/processor_perflib.c | 28 +- drivers/acpi/processor_throttling.c | 80 ++- drivers/base/cpu.c | 2 +- drivers/lguest/interrupts_and_traps.c | 13 +- drivers/pnp/pnpbios/bioscalls.c | 2 +- include/acpi/processor.h | 4 +- include/asm-m68k/bitops.h | 5 + include/linux/bitops.h | 13 +- include/linux/cpumask.h | 11 +- include/linux/interrupt.h | 2 +- include/linux/rcuclassic.h | 4 +- include/linux/sched.h | 92 ++- include/linux/stop_machine.h | 6 +- include/linux/tick.h | 4 +- include/linux/topology.h | 6 +- init/main.c | 13 +- kernel/compat.c | 49 +- kernel/cpu.c | 48 +- kernel/irq/manage.c | 11 +- kernel/irq/proc.c | 32 +- kernel/kexec.c | 2 +- kernel/power/poweroff.c | 2 +- kernel/profile.c | 38 +- kernel/rcuclassic.c | 31 +- kernel/rcupreempt.c | 19 +- kernel/rcutorture.c | 27 +- kernel/sched.c | 975 ++++++++++++++----------- kernel/sched_cpupri.c | 39 +- kernel/sched_cpupri.h | 5 +- kernel/sched_fair.c | 32 +- kernel/sched_rt.c | 74 ++- kernel/sched_stats.h | 3 +- kernel/smp.c | 2 +- kernel/softirq.c | 2 +- kernel/softlockup.c | 10 +- kernel/stop_machine.c | 8 +- kernel/taskstats.c | 39 +- kernel/time/clocksource.c | 9 +- kernel/time/tick-broadcast.c | 115 ++-- kernel/time/tick-common.c | 6 +- kernel/time/tick-sched.c | 10 +- kernel/trace/ring_buffer.c | 42 +- kernel/trace/trace.c | 72 ++- kernel/trace/trace.h | 2 +- kernel/trace/trace_boot.c | 2 +- kernel/trace/trace_functions_graph.c | 2 +- kernel/trace/trace_hw_branches.c | 6 +- kernel/trace/trace_power.c | 2 +- kernel/trace/trace_sysprof.c | 13 +- kernel/workqueue.c | 26 +- lib/Kconfig | 8 + lib/Makefile | 1 + lib/cpumask.c | 10 +- lib/find_last_bit.c | 45 ++ mm/pdflush.c | 16 +- mm/slab.c | 2 +- mm/slub.c | 20 +- mm/vmscan.c | 4 +- mm/vmstat.c | 4 +- security/selinux/selinuxfs.c | 2 +- 135 files changed, 2499 insertions(+), 1584 deletions(-) create mode 100644 lib/find_last_bit.c
Quoted 5 lines · Mike Travis
Hi Ingo,
Here's the latest cpumask updates which includes the latest merge from Rusty's cpumask tree.
Pulled into tip/cpus4096, thanks Mike.
Rusty already sent the pull request to Linus for his latest cpumask bits - is it fine if that goes upstream first and we do the second phase of the cpus4096 tree after that point?
Also, while testing tip/master i noticed that a couple of architectures wouldnt build due to cpumask changes:
testing 21 architectures.
testing cris: -git: pass ( 28), -tip: FAIL ( 25) testing m32r: -git: pass ( 21), -tip: FAIL ( 31)
both build failures go like this:
/home/mingo/tip/lib/find_last_bit.c: In function 'find_last_bit':
/home/mingo/tip/lib/find_last_bit.c:38: error: implicit declaration of function '__fls' make[2]: *** [lib/find_last_bit.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [lib] Error 2
these architectures have no __fls() implementation ...
trouble should be expected on ~8 architectures:
for N in arch/*; do [ -d $N ] && ( printf "%-20s: " $N; cd $N; dgrep __fls |
wc -l; ); done | sort -t: -n -k +2arch/cris : 0 arch/frv : 0 arch/h8300 : 0 arch/m32r : 0 arch/m68k : 0 arch/mn10300 : 0 arch/um : 0 arch/xtensa : 0 arch/arm : 1 arch/avr32 : 1 arch/blackfin : 1 arch/ia64 : 1 arch/m68knommu : 1 arch/parisc : 1 arch/powerpc : 1 arch/s390 : 1 arch/sh : 1 arch/x86 : 1 arch/alpha : 2 arch/sparc : 2 arch/mips : 5
Ingo
Quoted 4 lines · Ingo Molnar
Quoted 2 lines · Mike Travis
Hi Ingo,
Quoted 8 lines
Quoted 2 lines
Here's the latest cpumask updates which includes the latest merge from Rusty's cpumask tree.
Pulled into tip/cpus4096, thanks Mike.
Rusty already sent the pull request to Linus for his latest cpumask bits - is it fine if that goes upstream first and we do the second phase of the cpus4096 tree after that point?
As in the bits included in this pull request, or as in the last set of cpumask changes yet to be pushed to you? (Either is fine with me, just let me know what you want me to do.)
Quoted 17 lines
Also, while testing tip/master i noticed that a couple of architectures wouldnt build due to cpumask changes:
testing 21 architectures.
testing cris: -git: pass ( 28), -tip: FAIL ( 25) testing m32r: -git: pass ( 21), -tip: FAIL ( 31)both build failures go like this:
/home/mingo/tip/lib/find_last_bit.c: In function 'find_last_bit':
/home/mingo/tip/lib/find_last_bit.c:38: error: implicit declaration of function '__fls' make[2]: *** [lib/find_last_bit.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [lib] Error 2
Quoted 3 lines
these architectures have no
__fls()implementation ...trouble should be expected on ~8 architectures:
I'll leave this to Rusty, as it's his baby. (Is there an echo in here? ;-)
Thanks,
Mike
Quoted 27 lines
for N in arch/*; do [ -d $N ] && ( printf "%-20s: " $N; cd $N; dgrep __fls | wc -l; ); done | sort -t: -n -k +2arch/cris : 0 arch/frv : 0 arch/h8300 : 0 arch/m32r : 0 arch/m68k : 0 arch/mn10300 : 0 arch/um : 0 arch/xtensa : 0 arch/arm : 1 arch/avr32 : 1 arch/blackfin : 1 arch/ia64 : 1 arch/m68knommu : 1 arch/parisc : 1 arch/powerpc : 1 arch/s390 : 1 arch/sh : 1 arch/x86 : 1 arch/alpha : 2 arch/sparc : 2 arch/mips : 5Ingo
Quoted 1 line · On Saturday 03 January 2009 04:39:42 Ingo Molnar wrote:
these architectures have no
__fls()implementation ...
...
Quoted 8 lines
arch/cris : 0 arch/frv : 0 arch/h8300 : 0 arch/m32r : 0 arch/m68k : 0 arch/mn10300 : 0 arch/um : 0 arch/xtensa : 0
These are the non-linux-next archs.
I've already patched m68k (but it's in include/asm-m68k) and um doesn't need it.
Fixes are below, and pushed into my cpumask git tree.
Thanks,
Rusty.
commit 5ece5c5192d065c229da01e7b347c1d3877b59fa
Author: Rusty Russell <[email protected]> Date: Sat Jan 3 16:21:08 2009 +1030
xtensa: define __fls
Like fls, but can't be handed 0 and returns the bit number.
include/asm-xtensa/bitops.h +11 -0
@@ -82,6 +82,16 @@ static inline int fls (unsigned int x) return 32 - __cntlz(x); } +/** +* __fls - find last (most-significant) set bit in a long word +* @word: the word to search +* +* Undefined if no set bit exists, so code should check against 0 first. +*/ +static inline unsigned long __fls (unsigned long word) +{ +return 31 -__cntlz (word); +}#else /* Use the generic implementation if we don't have the nsa/nsau instructions. */
@@ -90,6 +100,7 @@ static inline int fls (unsigned int x)# include <asm-generic/bitops/__ffs.h> # include <asm-generic/bitops/ffz.h> # include <asm-generic/bitops/fls.h> +# include <asm-generic/bitops/__fls.h> #endif
commit 5c134dad43443aa9c9606eaf47c378a6b9c5c597
Author: Rusty Russell <[email protected]> Date: Sat Jan 3 16:19:03 2009 +1030
mn10300: define __fls
Like fls, but can't be handed 0 and returns the bit number.
include/asm-mn10300/bitops.h +11 -0
@@ -196,6 +196,17 @@ int fls(int x) }/** +* __fls - find last (most-significant) set bit in a long word +* @word: the word to search +* +* Undefined if no set bit exists, so code should check against 0 first. +*/ +static inline unsigned long __fls (unsigned long word) +{ +return __ilog2_u32 (word); +} + +/** * ffs - find first bit set * @x: the word to search *
commit 16a206260ee70f181de6a3672678545859589ef2
Author: Rusty Russell <[email protected]> Date: Sat Jan 3 16:16:54 2009 +1030
m32r: define __fls
Like fls, but can't be handed 0 and returns the bit number.
include/asm-m32r/bitops.h +1 -0
@@ -251,6 +251,7 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)#include <asm-generic/bitops/ffz.h> #include <asm-generic/bitops/__ffs.h> #include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> #include <asm-generic/bitops/fls64.h> #ifdef __KERNEL__
commit 9ddabc2a29163e4b243d10c5e06fc5584073d7ad
Author: Rusty Russell <[email protected]> Date: Sat Jan 3 16:16:04 2009 +1030
h8300: define __fls
Like fls, but can't be handed 0 and returns the bit number.
arch/h8300/include/asm/bitops.h +1 -0
@@ -207,6 +207,7 @@ static __inline__ unsigned long __ffs(unsigned long word)#endif /* __KERNEL__ */ #include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> #include <asm-generic/bitops/fls64.h> #endif /* _H8300_BITOPS_H */
commit ee38e5140bafbf40e1bd25ab917ac8db54a27799
Author: Rusty Russell <[email protected]> Date: Sat Jan 3 16:14:05 2009 +1030
frv: define __fls
Like fls, but can't be handed 0 and returns the bit number.
include/asm-frv/bitops.h +13 -0
@@ -339,6 +339,19 @@ int __ffs(unsigned long x)return 31 - bit; } +/** +* __fls - find last (most-significant) set bit in a long word +* @word: the word to search +* +* Undefined if no set bit exists, so code should check against 0 first. +*/ +static inline unsigned long __fls (unsigned long word) +{ +unsigned long bit; + asm("scan %1,gr0,%0" :"=r" (bit) :"r" (word)); +return bit; +} +/* * special slimline version of fls() for calculating ilog2_u32() * - note: no protection against n == 0
Hi Rusty,
Quoted 11 lines · On Sat, 3 Jan 2009 16:31:46 +1030 Rusty Russell <[email protected]> wrote:
Quoted 9 lines
arch/cris : 0 arch/frv : 0 arch/h8300 : 0 arch/m32r : 0 arch/m68k : 0 arch/mn10300 : 0 arch/um : 0 arch/xtensa : 0These are the non-linux-next archs.
linux-next does include (in theory) cris, m68k and xtensa. I don't, however, have a cris cross compiler. And now I need a new sh cross compiler. :-(
Signature · 3 lines
Cheers, Stephen Rothwell [email protected] http://www.canb.auug.org.au/~sfr/
Quoted 13 lines · On Saturday 03 January 2009 16:48:38 Stephen Rothwell wrote:
Hi Rusty,
Quoted 10 lines · On Sat, 3 Jan 2009 16:31:46 +1030 Rusty Russell <[email protected]> wrote:
Quoted 9 lines
arch/cris : 0 arch/frv : 0 arch/h8300 : 0 arch/m32r : 0 arch/m68k : 0 arch/mn10300 : 0 arch/um : 0 arch/xtensa : 0
Quoted 3 lines
Quoted 1 line
These are the non-linux-next archs.
linux-next does include (in theory) cris, m68k and xtensa.
m68k was actually OK, and xtensa did show the __fls issue (but it seems broken by something else as well).
BTW, do you send mail automagically when something breaks, or does one have to check the web page?
Thanks,
Rusty.
Hi Rusty,
Quoted 3 lines · On Sat, 3 Jan 2009 20:33:24 +1030 Rusty Russell <[email protected]> wrote:
BTW, do you send mail automagically when something breaks, or does one have to check the web page?
The infrastructure (kissb) doesn't have a notification facility but I might suggest it to Michael. Sometimes (when I have time) I check out the results and report anything interesting. Otherwise, I expect interested people will check every now and then.
Maybe more publicity is needed (though I do mention it in the daily release announcements).
Signature · 3 lines
Cheers, Stephen Rothwell [email protected] http://www.canb.auug.org.au/~sfr/