diff options
| author | David S. Miller <davem@nuts.ninka.net> | 2003-07-20 08:52:43 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-07-20 08:52:43 -0700 |
| commit | 764cf56e6ddb2a5ed92b73cf6e0b71f611302273 (patch) | |
| tree | e2a7855e76914435e3f91a16304b0b48590e919b | |
| parent | d7cd83673b6a522b47586cf8d09144caadcef396 (diff) | |
| parent | 50692f8c6b6a27ffed9b5b7206ca6682a60ff354 (diff) | |
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
42 files changed, 506 insertions, 177 deletions
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index d6dce76e594e..01a3990182c5 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -42,6 +42,7 @@ #include <asm/edd.h> #include <asm/setup.h> #include <asm/arch_hooks.h> +#include <asm/sections.h> #include "setup_arch_pre.h" #include "mach_resources.h" @@ -100,7 +101,7 @@ extern void early_cpu_init(void); extern void dmi_scan_machine(void); extern void generic_apic_probe(char *); extern int root_mountflags; -extern char _text, _etext, _edata, _end; +extern char _end[]; unsigned long saved_videomode; @@ -676,7 +677,7 @@ static unsigned long __init setup_memory(void) * partially used pages are not usable - thus * we are rounding upwards: */ - start_pfn = PFN_UP(__pa(&_end)); + start_pfn = PFN_UP(__pa(_end)); find_max_pfn(); @@ -947,15 +948,15 @@ void __init setup_arch(char **cmdline_p) if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) &_text; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; - - code_resource.start = virt_to_phys(&_text); - code_resource.end = virt_to_phys(&_etext)-1; - data_resource.start = virt_to_phys(&_etext); - data_resource.end = virt_to_phys(&_edata)-1; + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = virt_to_phys(_text); + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; parse_cmdline_early(cmdline_p); diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index daba5d620477..d991c2e3debc 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -562,7 +562,7 @@ void free_initmem(void) free_page(addr); totalram_pages++; } - printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); + printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (__init_end - __init_begin) >> 10); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 2af4669e3396..2f01619bf8ad 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -176,6 +176,8 @@ EXPORT_SYMBOL(up); /* Atomic counter implementation. */ EXPORT_SYMBOL(__atomic_add); EXPORT_SYMBOL(__atomic_sub); +EXPORT_SYMBOL(__atomic64_add); +EXPORT_SYMBOL(__atomic64_sub); #ifdef CONFIG_SMP EXPORT_SYMBOL(atomic_dec_and_lock); #endif diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 6aee8b7801ca..f4e9da69e146 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -41,6 +41,7 @@ #include <asm/isa.h> #include <asm/starfire.h> #include <asm/smp.h> +#include <asm/sections.h> spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -449,7 +450,6 @@ void sparc64_do_profile(struct pt_regs *regs) return; { - extern int _stext; extern int rwlock_impl_begin, rwlock_impl_end; extern int atomic_impl_begin, atomic_impl_end; extern int __memcpy_begin, __memcpy_end; @@ -468,7 +468,7 @@ void sparc64_do_profile(struct pt_regs *regs) pc < (unsigned long) &__bitops_end)) pc = o7; - pc -= (unsigned long) &_stext; + pc -= (unsigned long) _stext; pc >>= prof_shift; if(pc >= prof_len) diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S index 77be8b1f3e0c..13d68fd64d95 100644 --- a/arch/sparc64/lib/atomic.S +++ b/arch/sparc64/lib/atomic.S @@ -33,4 +33,27 @@ __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */ membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 + + .globl __atomic64_add +__atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ + ldx [%o1], %g5 + add %g5, %o0, %g7 + casx [%o1], %g5, %g7 + cmp %g5, %g7 + bne,pn %xcc, __atomic64_add + membar #StoreLoad | #StoreStore + retl + add %g7, %o0, %o0 + + .globl __atomic64_sub +__atomic64_sub: /* %o0 = increment, %o1 = atomic_ptr */ + ldx [%o1], %g5 + sub %g5, %o0, %g7 + casx [%o1], %g5, %g7 + cmp %g5, %g7 + bne,pn %xcc, __atomic64_sub + membar #StoreLoad | #StoreStore + retl + sub %g7, %o0, %o0 + atomic_impl_end: diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index e0a9cc52b831..348f206f0663 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -26,6 +26,7 @@ #include <asm/uaccess.h> #include <asm/asi.h> #include <asm/lsu.h> +#include <asm/sections.h> #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -320,10 +321,9 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs) if (regs->tstate & TSTATE_PRIV) { unsigned long tpc = regs->tpc; - extern unsigned int _etext; /* Sanity check the PC. */ - if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) || + if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) || (tpc >= MODULES_VADDR && tpc < MODULES_END)) { /* Valid, no problems... */ } else { diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 3f25da91293f..6127d73d1e8e 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -35,6 +35,7 @@ #include <asm/starfire.h> #include <asm/tlb.h> #include <asm/spitfire.h> +#include <asm/sections.h> DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -54,8 +55,8 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; -/* References to section boundaries */ -extern char __init_begin, __init_end, _start, _end, etext, edata; +/* References to special section boundaries */ +extern char _start[], _end[]; /* Initial ramdisk setup */ extern unsigned int sparc_ramdisk_image; @@ -1331,7 +1332,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) * image. The kernel is hard mapped below PAGE_OFFSET in a * 4MB locked TLB translation. */ - start_pfn = PAGE_ALIGN((unsigned long) &_end) - + start_pfn = PAGE_ALIGN((unsigned long) _end) - ((unsigned long) KERNBASE); /* Adjust up to the physical address where the kernel begins. */ @@ -1347,7 +1348,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) #ifdef CONFIG_BLK_DEV_INITRD /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ if (sparc_ramdisk_image) { - if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE) + if (sparc_ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE) sparc_ramdisk_image -= KERNBASE; initrd_start = sparc_ramdisk_image + phys_base; initrd_end = initrd_start + sparc_ramdisk_size; @@ -1424,7 +1425,7 @@ void __init paging_init(void) set_bit(0, mmu_context_bmap); - real_end = (unsigned long)&_end; + real_end = (unsigned long)_end; if ((real_end > ((unsigned long)KERNBASE + 0x400000))) bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD @@ -1716,7 +1717,7 @@ void __init mem_init(void) memset(sparc64_valid_addr_bitmap, 0, i << 3); addr = PAGE_OFFSET + phys_base; - last = PAGE_ALIGN((unsigned long)&_end) - + last = PAGE_ALIGN((unsigned long)_end) - ((unsigned long) KERNBASE); last += PAGE_OFFSET + phys_base; while (addr < last) { @@ -1743,11 +1744,11 @@ void __init mem_init(void) SetPageReserved(mem_map_zero); clear_page(page_address(mem_map_zero)); - codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); + codepages = (((unsigned long) _etext) - ((unsigned long) _start)); codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; - datapages = (((unsigned long) &edata) - ((unsigned long)&etext)); + datapages = (((unsigned long) _edata) - ((unsigned long) _etext)); datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT; - initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin)); + initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin)); initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; #ifndef CONFIG_SMP @@ -1810,8 +1811,8 @@ void free_initmem (void) /* * The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes. */ - addr = PAGE_ALIGN((unsigned long)(&__init_begin)); - initend = (unsigned long)(&__init_end) & PAGE_MASK; + addr = PAGE_ALIGN((unsigned long)(__init_begin)); + initend = (unsigned long)(__init_end) & PAGE_MASK; for (; addr < initend; addr += PAGE_SIZE) { unsigned long page; struct page *p; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 421750488515..fb0d28ee9ea6 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -222,9 +222,6 @@ MODULE_PARM(drive3, "1-7i"); #define ATAPI_READ_10 0x28 #define ATAPI_WRITE_10 0x2a -#ifdef MODULE -void cleanup_module(void); -#endif static int pf_open(struct inode *inode, struct file *file); static void do_pf_request(request_queue_t * q); static int pf_ioctl(struct inode *inode, struct file *file, diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 58534683cd03..429fb2955573 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -650,8 +650,6 @@ static unsigned int stli_baudrates[] = { */ #ifdef MODULE -int init_module(void); -void cleanup_module(void); static void stli_argbrds(void); static int stli_parsebrd(stlconf_t *confp, char **argp); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index f0b8aa4d1fc7..bf63034c0703 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -216,10 +216,7 @@ static struct timer_list moxaEmptyTimer[MAX_PORTS]; static struct semaphore moxaBuffSem; int moxa_init(void); -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#endif + /* * static functions: */ diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h index a59a045af441..91176b5097ab 100644 --- a/drivers/char/nwbutton.h +++ b/drivers/char/nwbutton.h @@ -32,10 +32,6 @@ int button_init (void); int button_add_callback (void (*callback) (void), int count); int button_del_callback (void (*callback) (void)); static void button_consume_callbacks (int bpcount); -#ifdef MODULE -int init_module (void); -void cleanup_module (void); -#endif /* MODULE */ #else /* Not compiling the driver itself */ diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 6789262c625e..430c3dd743e4 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -209,17 +209,9 @@ static void cleanup_board_resources(void) #ifdef MODULE -/* - * pcxe_init() is our init_module(): - */ -#define pcxe_init init_module - -void cleanup_module(void); - - /*****************************************************************************/ -void cleanup_module() +static void pcxe_cleanup() { unsigned long flags; @@ -240,6 +232,12 @@ void cleanup_module() kfree(digi_channels); restore_flags(flags); } + +/* + * pcxe_init() is our init_module(): + */ +module_init(pcxe_init); +module_cleanup(pcxe_cleanup); #endif static inline struct channel *chan(register struct tty_struct *tty) diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index cc443e25168e..4f066afb3ba7 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -472,8 +472,6 @@ static unsigned int stl_baudrates[] = { */ #ifdef MODULE -int init_module(void); -void cleanup_module(void); static void stl_argbrds(void); static int stl_parsebrd(stlconf_t *confp, char **argp); diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index fe58b5ff1d8e..4b81d1698e6a 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c @@ -16,6 +16,8 @@ * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts * from minutes to seconds. + * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in + * nwwatchdog_init. */ #include <linux/module.h> @@ -343,12 +345,14 @@ static struct miscdevice wdt977_miscdev= static int __init nwwatchdog_init(void) { + int retval; if (!machine_is_netwinder()) return -ENODEV; - misc_register(&wdt977_miscdev); - printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); - return 0; + retval = misc_register(&wdt977_miscdev); + if (!retval) + printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); + return retval; } static void __exit nwwatchdog_exit(void) diff --git a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c index 524c66f2597c..a947de74a926 100644 --- a/drivers/ieee1394/amdtp.c +++ b/drivers/ieee1394/amdtp.c @@ -62,6 +62,12 @@ * - Maybe make an ALSA interface, that is, create a file_ops * implementation that recognizes ALSA ioctls and uses defaults for * things that can't be controlled through ALSA (iso channel). + * + * Changes: + * + * - Audit copy_from_user in amdtp_write. + * Daniele Bellucci <bellucda@tiscali.it> + * */ #include <linux/module.h> @@ -1112,7 +1118,8 @@ static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count, for (i = 0; i < count; i += length) { p = buffer_put_bytes(s->input, count - i, &length); - copy_from_user(p, buffer + i, length); + if (copy_from_user(p, buffer + i, length)) + return -EFAULT; if (s->input->length < s->input->size) continue; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 952b0b9865e1..f8df5e1d669f 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -12,6 +12,10 @@ * Most of this code is directly derived from his userspace driver. * His driver works so send any reports to alan@redhat.com unless the * userspace driver also doesn't work for you... + * + * Changes: + * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> + * - pms_capture: report back -EFAULT */ #include <linux/module.h> @@ -659,7 +663,8 @@ static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) if(dt+len>count) dt=count-len; cnt += dev->height; - copy_to_user(buf, tmp+32, dt); + if (copy_to_user(buf, tmp+32, dt)) + return -EFAULT; buf += dt; len += dt; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index a1074f660875..984afdd8dd0d 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -474,10 +474,8 @@ static ssize_t vlsi_proc_read(struct file *file, char *buf, size_t nbytes, if (pos + nbytes > size) nbytes = size - pos; - if (!access_ok(VERIFY_WRITE, buf, nbytes)) - return -EINVAL; - - copy_to_user(buf, procdata->data + pos, nbytes); + if (copy_to_user(buf, procdata->data + pos, nbytes)) + return -EFAULT; *ppos += nbytes; diff --git a/drivers/net/wan/comx-hw-comx.c b/drivers/net/wan/comx-hw-comx.c index e57c8cf9dfca..17d797e727b1 100644 --- a/drivers/net/wan/comx-hw-comx.c +++ b/drivers/net/wan/comx-hw-comx.c @@ -11,6 +11,7 @@ * * Contributors: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 0.86 + * Daniele Bellucci <bellucda@tiscali.it> - 0.87 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,9 +43,12 @@ * - printk cleanups * Version 0.86 (00/08/15): * - resource release on failure at COMX_init + * + * Version 0.87 (03/07/09) + * - audit copy_from_user in comxhw_write_proc */ -#define VERSION "0.86" +#define VERSION "0.87" #include <linux/module.h> #include <linux/version.h> @@ -1084,7 +1088,8 @@ static int comxhw_write_proc(struct file *file, const char *buffer, if (hw->firmware->data) { kfree(hw->firmware->data); } - copy_from_user(tmp + file->f_pos, buffer, count); + if (copy_from_user(tmp + file->f_pos, buffer, count)) + return -EFAULT; hw->firmware->len = entry->size = file->f_pos + count; hw->firmware->data = tmp; file->f_pos += count; diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index b0e15cc9e3f9..5a4ceee9716f 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -160,10 +160,6 @@ /****** Function Prototypes *************************************************/ -/* Module entry points. These are called by the OS and must be public. */ -int init_module (void); -void cleanup_module (void); - /* Hardware-specific functions */ static int sdla_detect (sdlahw_t* hw); static int sdla_autodpm (sdlahw_t* hw); @@ -325,11 +321,7 @@ static int pci_slot_ar[MAX_S514_CARDS]; * Context: process */ -#ifdef MODULE -int init_module (void) -#else int sdladrv_init(void) -#endif { int i=0; @@ -354,9 +346,12 @@ int sdladrv_init(void) * Module 'remove' entry point. * o release all remaining system resources */ -void cleanup_module (void) +static void sdladrv_cleanup(void) { } + +module_init(sdladrv_init); +module_cleanup(sdladrv_cleanup); #endif /******* Kernel APIs ********************************************************/ diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c index 173810a600e7..de695ac6ff6e 100644 --- a/drivers/net/wan/sdlamain.c +++ b/drivers/net/wan/sdlamain.c @@ -177,10 +177,6 @@ static void dbg_kfree(void * v, int line) { extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/* Module entry points */ -int init_module (void); -void cleanup_module (void); - /* WAN link driver entry points */ static int setup(struct wan_device* wandev, wandev_conf_t* conf); static int shutdown(struct wan_device* wandev); @@ -246,11 +242,7 @@ static int wanpipe_bh_critical=0; * Context: process */ -#ifdef MODULE -int init_module (void) -#else int wanpipe_init(void) -#endif { int cnt, err = 0; @@ -313,7 +305,7 @@ int wanpipe_init(void) * o unregister all adapters from the WAN router * o release all remaining system resources */ -void cleanup_module (void) +static void wanpipe_cleanup(void) { int i; @@ -329,6 +321,8 @@ void cleanup_module (void) printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); } +module_init(wanpipe_init); +module_exit(wanpipe_cleanup); #endif /******* WAN Device Driver Entry Points *************************************/ diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 83630b0e59b5..a73dcffa4957 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -25,6 +25,8 @@ * - reorganize kmallocs in ray_attach, checking all for failure * and releasing the previous allocations if one fails * + * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003 + * - Audit copy_to_user in ioctl(SIOCGIWESSID) * =============================================================================*/ @@ -1315,7 +1317,8 @@ static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Push it out ! */ wrq->u.data.length = strlen(essid) + 1; wrq->u.data.flags = 1; /* active */ - copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)); + if (copy_to_user(wrq->u.data.pointer, essid, sizeof(essid))) + err = -EFAULT; } break; diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 69a53774882d..d164351b4925 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -14,6 +14,10 @@ * TODO: * - speed-up calculations with inlined assembler * - interface to write to second row of LCD from /proc (if technically possible) + * + * Changes: + * - Audit copy_from_user in led_proc_write. + * Daniele Bellucci <bellucda@tiscali.it> */ #include <linux/config.h> @@ -160,7 +164,9 @@ static int led_proc_write(struct file *file, const char *buf, memset(lbuf, 0, count); - copy_from_user(lbuf, buf, count); + if (copy_from_user(lbuf, buf, count)) + return -EFAULT; + cur = lbuf; /* skip initial spaces */ diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index ab8641e98b23..da05d2635f5e 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -14,6 +14,9 @@ * * EB - Added support for CP1500 Global Address and PS/Voltage monitoring. * Eric Brower <ebrower@usa.net> + * + * DB - Audit every copy_to_user in envctrl_read. + * Daniele Bellucci <bellucda@tiscali.it> */ #include <linux/config.h> @@ -571,7 +574,8 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) data[0] = (unsigned char)(warning_temperature); ret = 1; - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_SHUTDOWN_TEMPERATURE: @@ -580,14 +584,16 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) data[0] = (unsigned char)(shutdown_temperature); ret = 1; - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_MTHRBD_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_MTHRBDTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_MTHRBDTEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_CPU_TEMPERATURE: @@ -596,7 +602,8 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUTEMP_MON, data); /* Reset cpu to the default cpu0. */ - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_CPU_VOLTAGE: @@ -605,21 +612,24 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUVOLTAGE_MON, data); /* Reset cpu to the default cpu0. */ - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_SCSI_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_SCSITEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_SCSITEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_ETHERNET_TEMPERATURE: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_ETHERTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_ETHERTEMP_MON, data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_FAN_STATUS: @@ -627,7 +637,8 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_fan_status(pchild,data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_GLOBALADDRESS: @@ -635,7 +646,8 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_globaladdr(pchild, data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; case ENVCTRL_RD_VOLTAGE_STATUS: @@ -645,7 +657,8 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_voltage_status(pchild, data[0], data); - copy_to_user((unsigned char *)buf, data, ret); + if (copy_to_user((unsigned char *)buf, data, ret)) + ret = -EFAULT; break; default: diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 74d68c51b957..f51308d086db 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -23,6 +23,7 @@ * Fixes: David Huggins-Daines, <dhd@cepstral.com> * Fabio Ferrari, <fabio.ferrari@digitro.com.br> * Artis Kugevics, <artis@mt.lv> + * Daniele Bellucci, <bellucda@tiscali.it> * * More information about the hardware related to this driver can be found * at our website: http://www.quicknet.net @@ -45,6 +46,10 @@ static char ixj_c_revision[] = "$Revision: 4.7 $"; /* * $Log: ixj.c,v $ + * + * Revision 4.8 2003/07/09 19:39:00 Daniele Bellucci + * Audit some copy_*_user and minor cleanup. + * * Revision 4.7 2001/08/13 06:19:33 craigs * Added additional changes from Alan Cox and John Anderson for * 2.2 to 2.4 cleanup and bounds checking @@ -363,12 +368,9 @@ static IXJ ixj[IXJMAX]; static IXJ *ixj_alloc(void) { int cnt; - for(cnt=0; cnt<IXJMAX; cnt++) - { + for(cnt=0; cnt<IXJMAX; cnt++) { if(!ixj[cnt].DSPbase) - { return &ixj[cnt]; - } } return NULL; } @@ -6260,9 +6262,11 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, break; case IXJCTL_CIDCW: if(arg) { - copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID)); - } - else { + if (copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) { + retval = -EFAULT; + break; + } + } else { memset(&j->cid_send, 0, sizeof(PHONE_CID)); } ixj_write_cidcw(j); @@ -6273,14 +6277,12 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, /* Fall through */ case PHONE_RING_START: if(arg) { - if(copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) - { + if (copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID))) { retval = -EFAULT; break; } ixj_write_cid(j); - } - else { + } else { memset(&j->cid_send, 0, sizeof(PHONE_CID)); } ixj_ring_start(j); @@ -6696,7 +6698,8 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, case IXJCTL_SET_FILTER_RAW: if (copy_from_user(&jfr, (char *) arg, sizeof(jfr))) retval = -EFAULT; - retval = ixj_init_filter_raw(j, &jfr); + else + retval = ixj_init_filter_raw(j, &jfr); break; case IXJCTL_GET_FILTER_HIST: if(arg<0||arg>3) @@ -6705,8 +6708,10 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, retval = j->filter_hist[arg]; break; case IXJCTL_INIT_TONE: - copy_from_user(&ti, (char *) arg, sizeof(ti)); - retval = ixj_init_tone(j, &ti); + if (copy_from_user(&ti, (char *) arg, sizeof(ti))) + retval = -EFAULT; + else + retval = ixj_init_tone(j, &ti); break; case IXJCTL_TONE_CADENCE: retval = ixj_build_cadence(j, (IXJ_CADENCE *) arg); @@ -6715,8 +6720,10 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, retval = ixj_build_filter_cadence(j, (IXJ_FILTER_CADENCE *) arg); break; case IXJCTL_SIGCTL: - if (copy_from_user(&j->sigdef, (char *)arg, sizeof(IXJ_SIGDEF))) + if (copy_from_user(&j->sigdef, (char *)arg, sizeof(IXJ_SIGDEF))) { retval = -EFAULT; + break; + } j->ixj_signals[j->sigdef.event] = j->sigdef.signal; if(j->sigdef.event < 33) { raise = 1; @@ -7693,7 +7700,7 @@ MODULE_DESCRIPTION("Quicknet VoIP Telephony card module - www.quicknet.net"); MODULE_AUTHOR("Ed Okerson <eokerson@quicknet.net>"); MODULE_LICENSE("GPL"); -void ixj_exit(void) +static void __exit ixj_exit(void) { cleanup(); } @@ -7852,7 +7859,7 @@ int __init ixj_probe_pci(int *cnt) return probe; } -int __init ixj_init(void) +static int __init ixj_init(void) { int cnt = 0; int probe = 0; diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 54a3e5a9dc49..060f20ef11f1 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -1445,12 +1445,6 @@ int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) va_list args; int error, n; - if (!S_ISBLK(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, buf); - return -EINVAL; - } - va_start(args, fmt); n = vsnprintf(buf, 64, fmt, args); if (n >= 64 || !buf[0]) { @@ -1458,6 +1452,12 @@ int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) __FUNCTION__); return -EINVAL; } + + if (!S_ISBLK(mode)) { + printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", + __FUNCTION__, mode, buf); + return -EINVAL; + } de = _devfs_prepare_leaf(&dir, buf, mode); if (!de) { @@ -1491,12 +1491,6 @@ int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) va_list args; int error, n; - if (!S_ISCHR(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, buf); - return -EINVAL; - } - va_start(args, fmt); n = vsnprintf(buf, 64, fmt, args); if (n >= 64 || !buf[0]) { @@ -1505,6 +1499,12 @@ int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) return -EINVAL; } + if (!S_ISCHR(mode)) { + printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", + __FUNCTION__, mode, buf); + return -EINVAL; + } + de = _devfs_prepare_leaf(&dir, buf, mode); if (!de) { printk(KERN_WARNING "%s: could not prepare leaf for %s\n", diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 6f3f77110ead..14f12cc1ad8f 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -187,8 +187,9 @@ nlmclnt_recovery(struct nlm_host *host, u32 newstate) } else { nlmclnt_prepare_reclaim(host, newstate); nlm_get_host(host); - MOD_INC_USE_COUNT; - kernel_thread(reclaimer, host, CLONE_KERNEL); + __module_get(THIS_MODULE); + if (kernel_thread(reclaimer, host, CLONE_KERNEL)) + module_put(THIS_MODULE); } } @@ -244,7 +245,5 @@ restart: nlm_release_host(host); lockd_down(); unlock_kernel(); - MOD_DEC_USE_COUNT; - - return 0; + module_put_and_exit(0); } diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 0bf32fd74efc..63b8f1062092 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -88,7 +88,11 @@ lockd(struct svc_rqst *rqstp) unsigned long grace_period_expire; /* Lock module and set up kernel thread */ - MOD_INC_USE_COUNT; + /* lockd_up is waiting for us to startup, so will + * be holding a reference to this module, so it + * is safe to just claim another reference + */ + __module_get(THIS_MODULE); lock_kernel(); /* @@ -183,7 +187,7 @@ lockd(struct svc_rqst *rqstp) /* Release module */ unlock_kernel(); - MOD_DEC_USE_COUNT; + module_put_and_exit(0); } /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 1ba9f02f63e6..b783620ff9dd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -116,9 +116,12 @@ nfsd_svc(unsigned short port, int nrservs) nrservs -= (nfsd_serv->sv_nrthreads-1); while (nrservs > 0) { nrservs--; + __module_get(THIS_MODULE); error = svc_create_thread(nfsd, nfsd_serv); - if (error < 0) + if (error < 0) { + module_put(THIS_MODULE); break; + } } victim = nfsd_list.next; while (nrservs < 0 && victim != &nfsd_list) { @@ -175,7 +178,6 @@ nfsd(struct svc_rqst *rqstp) sigset_t shutdown_mask, allowed_mask; /* Lock module and set up kernel thread */ - MOD_INC_USE_COUNT; lock_kernel(); daemonize("nfsd"); current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; @@ -281,7 +283,7 @@ out: svc_exit_thread(rqstp); /* Release module */ - MOD_DEC_USE_COUNT; + module_put_and_exit(0); } int diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c index 323c2dbcccd0..fc300030afd1 100644 --- a/fs/umsdos/ioctl.c +++ b/fs/umsdos/ioctl.c @@ -4,6 +4,10 @@ * Written 1993 by Jacques Gelinas * * Extended MS-DOS ioctl directory handling functions + * + * Changes: + * 11/07/2003 Daniele Bellucci <bellucda@tiscali.it> + * - audit copy_to_user/put_user in umsdos_ioctl_fill. */ #include <asm/uaccess.h> @@ -36,11 +40,12 @@ static int umsdos_ioctl_fill ( struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; if (d->count == 0) { - copy_to_user (d->ent->d_name, name, name_len); - put_user ('\0', d->ent->d_name + name_len); - put_user (name_len, &d->ent->d_reclen); - put_user (ino, &d->ent->d_ino); - put_user (offset, &d->ent->d_off); + if (copy_to_user (d->ent->d_name, name, name_len) || + put_user ('\0', d->ent->d_name + name_len) || + put_user (name_len, &d->ent->d_reclen) || + put_user (ino, &d->ent->d_ino) || + put_user (offset, &d->ent->d_off)) + return -EFAULT; d->count = 1; ret = 0; } diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 12c067c8355d..0a366b54e2c5 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -375,7 +375,7 @@ shortname_info_to_lcase(struct shortname_info *base, } static inline int to_shortname_char(struct nls_table *nls, - char *buf, int buf_size, wchar_t *src, + unsigned char *buf, int buf_size, wchar_t *src, struct shortname_info *info) { int len; diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h new file mode 100644 index 000000000000..45c07dbc0a59 --- /dev/null +++ b/include/asm-generic/local.h @@ -0,0 +1,118 @@ +#ifndef _ASM_GENERIC_LOCAL_H +#define _ASM_GENERIC_LOCAL_H + +#include <linux/config.h> +#include <linux/percpu.h> +#include <asm/types.h> +#include <asm/hardirq.h> + +/* An unsigned long type for operations which are atomic for a single + * CPU. Usually used in combination with per-cpu variables. */ + +#if BITS_PER_LONG == 32 && !defined(CONFIG_SPARC32) +/* Implement in terms of atomics. */ + +/* Don't use typedef: don't want them to be mixed with atomic_t's. */ +typedef struct +{ + atomic_t a; +} local_t; + +#define LOCAL_INIT(i) { ATOMIC_INIT(i) } + +#define local_read(l) ((unsigned long)atomic_read(&(l)->a)) +#define local_set(l,i) atomic_set((&(l)->a),(i)) +#define local_inc(l) atomic_inc(&(l)->a) +#define local_dec(l) atomic_dec(&(l)->a) +#define local_add(i,l) atomic_add((i),(&(l)->a)) +#define local_sub(i,l) atomic_sub((i),(&(l)->a)) + +/* Non-atomic variants, ie. preemption disabled and won't be touched + * in interrupt, etc. Some archs can optimize this case well. */ +#define __local_inc(l) local_set((l), local_read(l) + 1) +#define __local_dec(l) local_set((l), local_read(l) - 1) +#define __local_add(i,l) local_set((l), local_read(l) + (i)) +#define __local_sub(i,l) local_set((l), local_read(l) - (i)) + +#else /* ... can't use atomics. */ +/* Implement in terms of three variables. + Another option would be to use local_irq_save/restore. */ + +typedef struct +{ + /* 0 = in hardirq, 1 = in softirq, 2 = usermode. */ + unsigned long v[3]; +} local_t; + +#define _LOCAL_VAR(l) ((l)->v[!in_interrupt() + !in_irq()]) + +#define LOCAL_INIT(i) { { (i), 0, 0 } } + +static inline unsigned long local_read(local_t *l) +{ + return l->v[0] + l->v[1] + l->v[2]; +} + +static inline void local_set(local_t *l, unsigned long v) +{ + l->v[0] = v; + l->v[1] = l->v[2] = 0; +} + +static inline void local_inc(local_t *l) +{ + preempt_disable(); + _LOCAL_VAR(l)++; + preempt_enable(); +} + +static inline void local_dec(local_t *l) +{ + preempt_disable(); + _LOCAL_VAR(l)--; + preempt_enable(); +} + +static inline void local_add(unsigned long v, local_t *l) +{ + preempt_disable(); + _LOCAL_VAR(l) += v; + preempt_enable(); +} + +static inline void local_sub(unsigned long v, local_t *l) +{ + preempt_disable(); + _LOCAL_VAR(l) -= v; + preempt_enable(); +} + +/* Non-atomic variants, ie. preemption disabled and won't be touched + * in interrupt, etc. Some archs can optimize this case well. */ +#define __local_inc(l) ((l)->v[0]++) +#define __local_dec(l) ((l)->v[0]--) +#define __local_add(i,l) ((l)->v[0] += (i)) +#define __local_sub(i,l) ((l)->v[0] -= (i)) + +#endif /* Non-atomic implementation */ + +/* Use these for per-cpu local_t variables: on some archs they are + * much more efficient than these naive implementations. Note they take + * a variable (eg. mystruct.foo), not an address. + */ +#define cpu_local_read(v) local_read(&__get_cpu_var(v)) +#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) +#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) +#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) +#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) +#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) + +/* Non-atomic increments, ie. preemption disabled and won't be touched + * in interrupt, etc. Some archs can optimize this case well. + */ +#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v)) +#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v)) +#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) +#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) + +#endif /* _ASM_GENERIC_LOCAL_H */ diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index f13b44926e6a..96d909da9ae7 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -9,33 +9,34 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; /* Separate out the type, so (int[3], foo) works. */ #define DEFINE_PER_CPU(type, name) \ - __attribute__((__section__(".data.percpu"))) __typeof__(type) name##__per_cpu + __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name /* var is in discarded region: offset to particular copy we want */ -#define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu])) +#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) #define __get_cpu_var(var) per_cpu(var, smp_processor_id()) -static inline void percpu_modcopy(void *pcpudst, const void *src, - unsigned long size) -{ - unsigned int i; - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) - memcpy(pcpudst + __per_cpu_offset[i], src, size); -} +/* A macro to avoid #include hell... */ +#define percpu_modcopy(pcpudst, src, size) \ +do { \ + unsigned int __i; \ + for (__i = 0; __i < NR_CPUS; __i++) \ + if (cpu_possible(__i)) \ + memcpy((pcpudst)+__per_cpu_offset[__i], \ + (src), (size)); \ +} while (0) #else /* ! SMP */ #define DEFINE_PER_CPU(type, name) \ - __typeof__(type) name##__per_cpu + __typeof__(type) per_cpu__##name -#define per_cpu(var, cpu) ((void)cpu, var##__per_cpu) -#define __get_cpu_var(var) var##__per_cpu +#define per_cpu(var, cpu) ((void)cpu, per_cpu__##var) +#define __get_cpu_var(var) per_cpu__##var #endif /* SMP */ -#define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu +#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name -#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(var##__per_cpu) -#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(var##__per_cpu) +#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var) +#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var) #endif /* _ASM_GENERIC_PERCPU_H_ */ diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index fe290e3349be..ce400f39ba25 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -3,9 +3,10 @@ /* References to section boundaries */ -extern char _text, _etext; -extern char _data, _edata; -extern char __bss_start; -extern char __init_begin, __init_end; +extern char _text[], _stext[], _etext[]; +extern char _data[], _sdata[], _edata[]; +extern char __bss_start[]; +extern char __init_begin[], __init_end[]; +extern char _sinittext[], _einittext[]; #endif /* _ASM_GENERIC_SECTIONS_H_ */ diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 30e4cfa8395b..eaee6b7cd24f 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -16,6 +16,7 @@ #include <linux/profile.h> #include <asm/atomic.h> #include <asm/irq.h> +#include <asm/sections.h> /* * Various low-level irq details needed by irq.c, process.c, @@ -63,8 +64,6 @@ extern unsigned long io_apic_irqs; extern atomic_t irq_err_count; extern atomic_t irq_mis_count; -extern char _stext, _etext; - #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs)) /* @@ -95,7 +94,7 @@ static inline void x86_do_profile(struct pt_regs * regs) if (!((1<<smp_processor_id()) & prof_cpu_mask)) return; - eip -= (unsigned long) &_stext; + eip -= (unsigned long)_stext; eip >>= prof_shift; /* * Don't ignore out-of-bounds EIP values silently, diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h new file mode 100644 index 000000000000..0177da80dde3 --- /dev/null +++ b/include/asm-i386/local.h @@ -0,0 +1,70 @@ +#ifndef _ARCH_I386_LOCAL_H +#define _ARCH_I386_LOCAL_H + +#include <linux/percpu.h> + +typedef struct +{ + volatile unsigned long counter; +} local_t; + +#define LOCAL_INIT(i) { (i) } + +#define local_read(v) ((v)->counter) +#define local_set(v,i) (((v)->counter) = (i)) + +static __inline__ void local_inc(local_t *v) +{ + __asm__ __volatile__( + "incl %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + +static __inline__ void local_dec(local_t *v) +{ + __asm__ __volatile__( + "decl %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + +static __inline__ void local_add(unsigned long i, local_t *v) +{ + __asm__ __volatile__( + "addl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); +} + +static __inline__ void local_sub(unsigned long i, local_t *v) +{ + __asm__ __volatile__( + "subl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); +} + +/* On x86, these are no better than the atomic variants. */ +#define __local_inc(l) local_inc(l) +#define __local_dec(l) local_dec(l) +#define __local_add(i,l) local_add((i),(l)) +#define __local_sub(i,l) local_sub((i),(l)) + +/* Use these for per-cpu local_t variables: on some archs they are + * much more efficient than these naive implementations. Note they take + * a variable, not an address. + */ +#define cpu_local_read(v) local_read(&__get_cpu_var(v)) +#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) +#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) +#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) +#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) +#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) + +#define __cpu_local_inc(v) cpu_local_inc(v) +#define __cpu_local_dec(v) cpu_local_dec(v) +#define __cpu_local_add(i, v) cpu_local_add((i), (v)) +#define __cpu_local_sub(i, v) cpu_local_sub((i), (v)) + +#endif /* _ARCH_I386_LOCAL_H */ diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h index fc10b924f42e..ea155897855c 100644 --- a/include/asm-sparc64/atomic.h +++ b/include/asm-sparc64/atomic.h @@ -9,25 +9,46 @@ #define __ARCH_SPARC64_ATOMIC__ typedef struct { volatile int counter; } atomic_t; -#define ATOMIC_INIT(i) { (i) } +typedef struct { volatile long counter; } atomic64_t; + +#define ATOMIC_INIT(i) { (i) } +#define ATOMIC64_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) +#define atomic64_read(v) ((v)->counter) + #define atomic_set(v, i) (((v)->counter) = i) +#define atomic64_set(v, i) (((v)->counter) = i) extern int __atomic_add(int, atomic_t *); +extern int __atomic64_add(int, atomic64_t *); + extern int __atomic_sub(int, atomic_t *); +extern int __atomic64_sub(int, atomic64_t *); #define atomic_add(i, v) ((void)__atomic_add(i, v)) +#define atomic64_add(i, v) ((void)__atomic64_add(i, v)) + #define atomic_sub(i, v) ((void)__atomic_sub(i, v)) +#define atomic64_sub(i, v) ((void)__atomic64_sub(i, v)) #define atomic_dec_return(v) __atomic_sub(1, v) +#define atomic64_dec_return(v) __atomic64_sub(1, v) + #define atomic_inc_return(v) __atomic_add(1, v) +#define atomic64_inc_return(v) __atomic64_add(1, v) #define atomic_sub_and_test(i, v) (__atomic_sub(i, v) == 0) +#define atomic64_sub_and_test(i, v) (__atomic64_sub(i, v) == 0) + #define atomic_dec_and_test(v) (__atomic_sub(1, v) == 0) +#define atomic64_dec_and_test(v) (__atomic64_sub(1, v) == 0) #define atomic_inc(v) ((void)__atomic_add(1, v)) +#define atomic64_inc(v) ((void)__atomic64_add(1, v)) + #define atomic_dec(v) ((void)__atomic_sub(1, v)) +#define atomic64_dec(v) ((void)__atomic64_sub(1, v)) /* Atomic operations are already serializing */ #define smp_mb__before_atomic_dec() barrier() diff --git a/include/asm-sparc64/local.h b/include/asm-sparc64/local.h new file mode 100644 index 000000000000..49f543a8f11e --- /dev/null +++ b/include/asm-sparc64/local.h @@ -0,0 +1,40 @@ +#ifndef _ARCH_SPARC64_LOCAL_H +#define _ARCH_SPARC64_LOCAL_H + +#include <linux/percpu.h> +#include <asm/atomic.h> + +typedef atomic64_t local_t; + +#define LOCAL_INIT(i) ATOMIC64_INIT(i) +#define local_read(v) atomic64_read(v) +#define local_set(v,i) atomic64_set(v,i) + +#define local_inc(v) atomic64_inc(v) +#define local_dec(v) atomic64_inc(v) +#define local_add(i, v) atomic64_add(i, v) +#define local_sub(i, v) atomic64_sub(i, v) + +#define __local_inc(v) ((v)->counter++) +#define __local_dec(v) ((v)->counter++) +#define __local_add(i,v) ((v)->counter+=(i)) +#define __local_sub(i,v) ((v)->counter-=(i)) + +/* Use these for per-cpu local_t variables: on some archs they are + * much more efficient than these naive implementations. Note they take + * a variable, not an address. + */ +#define cpu_local_read(v) local_read(&__get_cpu_var(v)) +#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) + +#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) +#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) +#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) +#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) + +#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v)) +#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v)) +#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) +#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) + +#endif /* _ARCH_SPARC64_LOCAL_H */ diff --git a/include/asm-sparc64/sections.h b/include/asm-sparc64/sections.h new file mode 100644 index 000000000000..e6dcceabffb2 --- /dev/null +++ b/include/asm-sparc64/sections.h @@ -0,0 +1,7 @@ +#ifndef _SPARC64_SECTIONS_H +#define _SPARC64_SECTIONS_H + +/* nothing to see, move along */ +#include <asm-generic/sections.h> + +#endif diff --git a/include/linux/module.h b/include/linux/module.h index 1d48f23a8a6a..13ff244afdbf 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -16,6 +16,7 @@ #include <linux/kmod.h> #include <linux/elf.h> #include <linux/stringify.h> +#include <asm/local.h> #include <asm/module.h> @@ -171,7 +172,7 @@ void *__symbol_get_gpl(const char *symbol); struct module_ref { - atomic_t count; + local_t count; } ____cacheline_aligned; enum module_state @@ -276,19 +277,17 @@ struct module *module_get_kallsym(unsigned int symnum, char *type, char namebuf[128]); int is_exported(const char *name, const struct module *mod); -#ifdef CONFIG_MODULE_UNLOAD +extern void __module_put_and_exit(struct module *mod, long code) + __attribute__((noreturn)); +#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); + +#ifdef CONFIG_MODULE_UNLOAD unsigned int module_refcount(struct module *mod); void __symbol_put(const char *symbol); #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) void symbol_put_addr(void *addr); -/* We only need protection against local interrupts. */ -#ifndef __HAVE_ARCH_LOCAL_INC -#define local_inc(x) atomic_inc(x) -#define local_dec(x) atomic_dec(x) -#endif - /* Sometimes we know we already have a refcount, and it's easier not to handle the error case (which only happens with rmmod --wait). */ static inline void __module_get(struct module *module) @@ -445,6 +444,8 @@ static inline int unregister_module_notifier(struct notifier_block * nb) return 0; } +#define module_put_and_exit(code) do_exit(code) + #endif /* CONFIG_MODULES */ #ifdef MODULE diff --git a/kernel/extable.c b/kernel/extable.c index d49099854024..6f1fb8c6b75b 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -17,10 +17,10 @@ */ #include <linux/module.h> #include <asm/uaccess.h> +#include <asm/sections.h> extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; -extern char _stext[], _etext[], _sinittext[], _einittext[]; /* Given an address, look for it in the exception tables. */ const struct exception_table_entry *search_exception_tables(unsigned long addr) diff --git a/kernel/module.c b/kernel/module.c index ea1cf83ee2b3..58d73701bbde 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -98,6 +98,17 @@ int init_module(void) } EXPORT_SYMBOL(init_module); +/* A thread that wants to hold a reference to a module only while it + * is running can call ths to safely exit. + * nfsd and lockd use this. + */ +void __module_put_and_exit(struct module *mod, long code) +{ + module_put(mod); + do_exit(code); +} +EXPORT_SYMBOL(__module_put_and_exit); + /* Find a module section: 0 means not found. */ static unsigned int find_sec(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, @@ -374,9 +385,9 @@ static void module_unload_init(struct module *mod) INIT_LIST_HEAD(&mod->modules_which_use_me); for (i = 0; i < NR_CPUS; i++) - atomic_set(&mod->ref[i].count, 0); + local_set(&mod->ref[i].count, 0); /* Hold reference count during initialization. */ - atomic_set(&mod->ref[smp_processor_id()].count, 1); + local_set(&mod->ref[smp_processor_id()].count, 1); /* Backwards compatibility macros put refcount during init. */ mod->waiter = current; } @@ -599,7 +610,7 @@ unsigned int module_refcount(struct module *mod) unsigned int i, total = 0; for (i = 0; i < NR_CPUS; i++) - total += atomic_read(&mod->ref[i].count); + total += local_read(&mod->ref[i].count); return total; } EXPORT_SYMBOL(module_refcount); @@ -610,7 +621,10 @@ static void free_module(struct module *mod); #ifdef CONFIG_MODULE_FORCE_UNLOAD static inline int try_force(unsigned int flags) { - return (flags & O_TRUNC); + int ret = (flags & O_TRUNC); + if (ret) + tainted |= TAINT_FORCED_MODULE; + return ret; } #else static inline int try_force(unsigned int flags) diff --git a/kernel/profile.c b/kernel/profile.c index 4f6d22ce33f2..5c02ac0fbbda 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -8,8 +8,7 @@ #include <linux/bootmem.h> #include <linux/notifier.h> #include <linux/mm.h> - -extern char _stext, _etext; +#include <asm/sections.h> unsigned int * prof_buffer; unsigned long prof_len; @@ -36,7 +35,7 @@ void __init profile_init(void) return; /* only text is profiled */ - prof_len = (unsigned long) &_etext - (unsigned long) &_stext; + prof_len = _etext - _stext; prof_len >>= prof_shift; size = prof_len * sizeof(unsigned int) + PAGE_SIZE - 1; |
