diff options
| author | Patrick Mochel <mochel@osdl.org> | 2003-01-06 23:38:43 -0600 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2003-01-06 23:38:43 -0600 |
| commit | eeacc9367455a3bbbed00ced63a06c65fe347784 (patch) | |
| tree | 55b12e320e6065468186214509cc08076e0fb32f | |
| parent | 351b11abdb0c25cb383b8e881939a6e2f3d64c28 (diff) | |
| parent | a34aca8a2ee295cc711418518f1d8c9fe099833d (diff) | |
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
182 files changed, 2535 insertions, 1548 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 11c194d9615d..4e689b702761 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -90,7 +90,7 @@ IMG-parportbook2 := $(addprefix $(obj)/,$(IMG-parportbook)) EPS-parportbook := $(patsubst %.fig,%.eps, $(IMG-parportbook2)) PNG-parportbook := $(patsubst %.fig,%.png, $(IMG-parportbook2)) $(obj)/parportbook.html: $(PNG-parportbook) -$(obj)/parportbook.ps $(obj)/parportbook.pdf: $(EPS-parportbook) +$(obj)/parportbook.ps $(obj)/parportbook.pdf: $(EPS-parportbook) $(PNG-parportbook) ### # Rules to generate postscript, PDF and HTML diff --git a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl index 3df30534a4bd..e57c8593eabd 100644 --- a/Documentation/DocBook/journal-api.tmpl +++ b/Documentation/DocBook/journal-api.tmpl @@ -206,6 +206,7 @@ eg. journal_unlock_updates() // carry on with filesystem use. </programlisting> +<para> The opportunities for abuse and DOS attacks with this should be obvious, if you allow unprivileged userspace to trigger codepaths containing these calls. @@ -250,7 +251,6 @@ an example. } journal_destroy(my_jrnl); </programlisting> -</para> </sect1> </chapter> diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index f7b088432595..74dd7dd4a51f 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -150,7 +150,12 @@ KAO --> !Ekernel/kmod.c </sect1> <sect1><title>Inter Module support</title> -!Ekernel/module.c + <para> + Refer to the file kernel/module.c for more information. + </para> +<!-- FIXME: Removed for now since no structured comments in source +X!Ekernel/module.c +--> </sect1> </chapter> @@ -172,7 +177,12 @@ KAO --> </sect1> <sect1><title>MCA Architecture</title> <sect2><title>MCA Device Functions</title> -!Earch/i386/kernel/mca.c + <para> + Refer to the file arch/i386/kernel/mca.c for more information. + </para> +<!-- FIXME: Removed for now since no structured comments in source +X!Earch/i386/kernel/mca.c +--> </sect2> <sect2><title>MCA Bus DMA</title> !Iinclude/asm-i386/mca_dma.h @@ -213,7 +223,9 @@ KAO --> <chapter id="snddev"> <title>Sound Devices</title> !Esound/sound_core.c -!Isound/sound_firmware.c +<!-- FIXME: Removed for now since no structured comments in source +X!Isound/sound_firmware.c +--> </chapter> <chapter id="usb"> @@ -292,7 +304,9 @@ KAO --> <sect1><title>USB Core APIs</title> !Edrivers/usb/core/urb.c -!Edrivers/usb/core/config.c +<!-- FIXME: Removed for now since no structured comments in source +X!Edrivers/usb/core/config.c +--> !Edrivers/usb/core/message.c !Edrivers/usb/core/file.c !Edrivers/usb/core/usb.c @@ -385,7 +399,12 @@ KAO --> !Idrivers/video/macmodes.c </sect1> <sect1><title>Frame Buffer Fonts</title> -!Idrivers/video/console/fonts.c + <para> + Refer to the file drivers/video/console/fonts.c for more information. + </para> +<!-- FIXME: Removed for now since no structured comments in source +X!Idrivers/video/console/fonts.c +--> </sect1> </chapter> <!-- Needs ksyms to list additional exported symbols, but no specific doc. diff --git a/Documentation/DocBook/scsidrivers.tmpl b/Documentation/DocBook/scsidrivers.tmpl index 1911dc943cec..1dbafa7c2bd9 100644 --- a/Documentation/DocBook/scsidrivers.tmpl +++ b/Documentation/DocBook/scsidrivers.tmpl @@ -52,7 +52,7 @@ level drivers can control one or more scsi hosts (a.k.a. scsi initiators). </para> <para> This document can been found in an ASCII text file in the linux kernel -source: <filename>drivers/scsi/scsi_mid_low_api.txt</filename> . +source: <filename>Documentation/scsi/scsi_mid_low_api.txt</filename> . It currently hold a little more information than this document. The <filename>drivers/scsi/hosts.h</filename> and <filename> drivers/scsi/scsi.h</filename> headers contain descriptions of members @@ -107,7 +107,7 @@ an existing lower level driver does in this regard. <chapter id="intfunctions"> <title>Interface Functions</title> -!Edrivers/scsi/scsi_mid_low_api.txt +!EDocumentation/scsi/scsi_mid_low_api.txt </chapter> <chapter id="locks"> diff --git a/Documentation/DocBook/videobook.tmpl b/Documentation/DocBook/videobook.tmpl index 11eb55fd5f07..de05ab79c79e 100644 --- a/Documentation/DocBook/videobook.tmpl +++ b/Documentation/DocBook/videobook.tmpl @@ -146,16 +146,17 @@ static int io = 0x320; int __init myradio_init(struct video_init *v) { - if(check_region(io, MY_IO_SIZE)) + if(!request_region(io, MY_IO_SIZE, "myradio")) { printk(KERN_ERR "myradio: port 0x%03X is in use.\n", io); return -EBUSY; } - if(video_device_register(&my_radio, VFL_TYPE_RADIO)==-1) + if(video_device_register(&my_radio, VFL_TYPE_RADIO)==-1) { + release_region(io, MY_IO_SIZE); return -EINVAL; - request_region(io, MY_IO_SIZE, "myradio"); + } return 0; } @@ -920,7 +921,7 @@ static int irq = 11; int __init mycamera_init(struct video_init *v) { - if(check_region(io, MY_IO_SIZE)) + if(!request_region(io, MY_IO_SIZE, "mycamera")) { printk(KERN_ERR "mycamera: port 0x%03X is in use.\n", io); @@ -928,9 +929,10 @@ int __init mycamera_init(struct video_init *v) } if(video_device_register(&my_camera, - VFL_TYPE_GRABBER)==-1) + VFL_TYPE_GRABBER)==-1) { + release_region(io, MY_IO_SIZE); return -EINVAL; - request_region(io, MY_IO_SIZE, "mycamera"); + } return 0; } diff --git a/MAINTAINERS b/MAINTAINERS index 9c9e21aebc61..0ff1129888a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1133,6 +1133,12 @@ W: http://www.acc.umu.se/~mcalinux/ L: linux-kernel@vger.kernel.org S: Maintained +MODULE SUPPORT +P: Rusty Russell +M: rusty@rustcorp.com.au +L: linux-kernel@vger.kernel.org +S: Maintained + MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER P: Stelian Pop M: stelian@popies.net diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index 79f400d4888f..d2fadd634e45 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -121,8 +121,10 @@ include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s archclean: $(Q)$(MAKE) -f scripts/Makefile.clean obj=$(boot) -CLEAN_FILES += include/asm-$(ARCH)/offset.h.tmp \ - include/asm-$(ARCH)/offset.h +archmrproper: + +CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h.tmp \ + include/asm-$(ARCH)/asm_offsets.h define archhelp echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)' diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index b22cbaeae0b8..d9523688bf66 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_VGA_HOSE) += console.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o obj-$(CONFIG_SRM_ENV) += srm_env.o +obj-$(CONFIG_MODULES) += module.o ifdef CONFIG_ALPHA_GENERIC diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c new file mode 100644 index 000000000000..0d3f1f35a937 --- /dev/null +++ b/arch/alpha/kernel/module.c @@ -0,0 +1,306 @@ +/* Kernel module help for Alpha. + Copyright (C) 2002 Richard Henderson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void * +module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +void +module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* Allocate the GOT at the end of the core sections. */ + +struct got_entry { + struct got_entry *next; + Elf64_Addr r_offset; + int got_offset; +}; + +static inline void +process_reloc_for_got(Elf64_Rela *rela, + struct got_entry *chains, Elf64_Xword *poffset) +{ + unsigned long r_sym = ELF64_R_SYM (rela->r_info); + unsigned long r_type = ELF64_R_TYPE (rela->r_info); + Elf64_Addr r_offset = rela->r_offset; + struct got_entry *g; + + if (r_type != R_ALPHA_LITERAL) + return; + + for (g = chains + r_sym; g ; g = g->next) + if (g->r_offset == r_offset) { + if (g->got_offset == 0) { + g->got_offset = *poffset; + *poffset += 8; + } + goto found_entry; + } + + g = kmalloc (sizeof (*g), GFP_KERNEL); + g->next = chains[r_sym].next; + g->r_offset = r_offset; + g->got_offset = *poffset; + *poffset += 8; + chains[r_sym].next = g; + + found_entry: + /* Trick: most of the ELF64_R_TYPE field is unused. There are + 42 valid relocation types, and a 32-bit field. Co-opt the + bits above 256 to store the got offset for this reloc. */ + rela->r_info |= g->got_offset << 8; +} + +int +module_frob_arch_sections(const Elf64_Ehdr *hdr, const Elf64_Shdr *sechdrs, + const char *secstrings, struct module *me) +{ + struct got_entry *chains; + Elf64_Rela *rela; + const Elf64_Shdr *esechdrs, *symtab, *s; + Elf64_Shdr *got; + unsigned long nsyms, nrela, i; + + esechdrs = sechdrs + hdr->e_shnum; + symtab = got = NULL; + + /* Find out how large the symbol table is. Allocate one got_entry + head per symbol. Normally this will be enough, but not always. + We'll chain different offsets for the symbol down each head. */ + for (s = sechdrs; s < esechdrs; ++s) + if (s->sh_type == SHT_SYMTAB) + symtab = s; + else if (!strcmp(".got", secstrings + s->sh_name)) { + got = (Elf64_Shdr *) s; + me->arch.gotsecindex = s - sechdrs; + } + + if (!symtab) { + printk(KERN_ERR "module %s: no symbol table\n", me->name); + return -ENOEXEC; + } + if (!got) { + printk(KERN_ERR "module %s: no got section\n", me->name); + return -ENOEXEC; + } + + nsyms = symtab->sh_size / sizeof(Elf64_Sym); + chains = kmalloc(nsyms * sizeof(struct got_entry), GFP_KERNEL); + memset(chains, 0, nsyms * sizeof(struct got_entry)); + + got->sh_size = 0; + got->sh_addralign = 8; + got->sh_type = SHT_NOBITS; + + /* Examine all LITERAL relocations to find out what GOT entries + are required. This sizes the GOT section as well. */ + for (s = sechdrs; s < esechdrs; ++s) + if (s->sh_type == SHT_RELA) { + nrela = s->sh_size / sizeof(Elf64_Rela); + rela = (void *)hdr + s->sh_offset; + for (i = 0; i < nrela; ++i) + process_reloc_for_got(rela+i, chains, + &got->sh_size); + } + + /* Free the memory we allocated. */ + for (i = 0; i < nsyms; ++i) { + struct got_entry *g, *n; + for (g = chains[i].next; g ; g = n) { + n = g->next; + kfree(g); + } + } + kfree(chains); + + return 0; +} + +int +apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, + unsigned int relsec, struct module *me) +{ + printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); + return -ENOEXEC; +} + +int +apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *me) +{ + Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; + unsigned long i, n = sechdrs[relsec].sh_size / sizeof(*rela); + Elf64_Sym *symtab, *sym; + void *base, *location; + unsigned long got, gp; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + base = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr; + symtab = (Elf64_Sym *)sechdrs[symindex].sh_addr; + + /* The small sections were sorted to the end of the segment. + The following should definitely cover them. */ + gp = (u64)me->module_core + me->core_size - 0x8000; + got = sechdrs[me->arch.gotsecindex].sh_addr; + + for (i = 0; i < n; i++) { + unsigned long r_sym = ELF64_R_SYM (rela[i].r_info); + unsigned long r_type = ELF64_R_TYPE (rela[i].r_info); + unsigned long r_got_offset = r_type >> 8; + unsigned long value, hi, lo; + r_type &= 0xff; + + /* This is where to make the change. */ + location = base + rela[i].r_offset; + + /* This is the symbol it is referring to. */ + sym = symtab + r_sym; + value = sym->st_value; + if (!value) { + printk(KERN_ERR "module %s: Unknown symbol %s\n", + me->name, strtab + sym->st_name); + return -ENOENT; + } + value += rela[i].r_addend; + + switch (r_type) { + case R_ALPHA_NONE: + break; + case R_ALPHA_REFQUAD: + *(u64 *)location = value; + break; + case R_ALPHA_GPREL32: + value -= gp; + if ((int)value != value) + goto reloc_overflow; + *(u32 *)location = value; + break; + case R_ALPHA_LITERAL: + hi = got + r_got_offset; + lo = hi - gp; + if ((short)lo != lo) + goto reloc_overflow; + *(u16 *)location = lo; + *(u64 *)hi = value; + break; + case R_ALPHA_LITUSE: + break; + case R_ALPHA_GPDISP: + value = gp - (u64)location; + lo = (short)value; + hi = (int)(value - lo); + if (hi + lo != value) + goto reloc_overflow; + *(u16 *)location = hi >> 16; + *(u16 *)(location + rela[i].r_addend) = lo; + break; + case R_ALPHA_BRSGP: + /* BRSGP is only allowed to bind to local symbols. + If the section is undef, this means that the + value was resolved from somewhere else. */ + if (sym->st_shndx == SHN_UNDEF) + goto reloc_overflow; + /* FALLTHRU */ + case R_ALPHA_BRADDR: + value -= (u64)location + 4; + if (value & 3) + goto reloc_overflow; + value = (long)value >> 2; + if (value + (1<<21) >= 1<<22) + goto reloc_overflow; + value &= 0x1fffff; + value |= *(u32 *)location & ~0x1fffff; + *(u32 *)location = value; + break; + case R_ALPHA_HINT: + break; + case R_ALPHA_SREL32: + value -= (u64)location; + if ((int)value != value) + goto reloc_overflow; + *(u32 *)location = value; + break; + case R_ALPHA_SREL64: + value -= (u64)location; + *(u64 *)location = value; + break; + case R_ALPHA_GPRELHIGH: + value = (value - gp + 0x8000) >> 16; + if ((short) value != value) + goto reloc_overflow; + *(u16 *)location = value; + break; + case R_ALPHA_GPRELLOW: + value -= gp; + *(u16 *)location = value; + break; + case R_ALPHA_GPREL16: + value -= gp; + if ((short) value != value) + goto reloc_overflow; + *(u16 *)location = value; + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %lu\n", + me->name, r_type); + return -ENOEXEC; + reloc_overflow: + if (ELF64_ST_TYPE (sym->st_info) == STT_SECTION) + printk(KERN_ERR + "module %s: Relocation overflow vs section %d\n", + me->name, sym->st_shndx); + else + printk(KERN_ERR + "module %s: Relocation overflow vs %s\n", + me->name, strtab + sym->st_name); + return -ENOEXEC; + } + } + + return 0; +} + +int +module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 7f30895ca719..4963bab746af 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -14,6 +14,7 @@ #include <linux/tty.h> #include <linux/delay.h> #include <linux/smp_lock.h> +#include <linux/module.h> #include <asm/gentrap.h> #include <asm/uaccess.h> @@ -465,7 +466,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, { long error, tmp1, tmp2, tmp3, tmp4; unsigned long pc = regs.pc - 4; - unsigned fixup; + const struct exception_table_entry *fixup; unaligned[0].count++; unaligned[0].va = (unsigned long) va; @@ -638,7 +639,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, got_exception: /* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ - if ((fixup = search_exception_table(pc)) != 0) { + if ((fixup = search_exception_tables(pc)) != 0) { unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c index c856eea015f3..310c9fd5604f 100644 --- a/arch/alpha/mm/extable.c +++ b/arch/alpha/mm/extable.c @@ -6,13 +6,10 @@ #include <linux/module.h> #include <asm/uaccess.h> -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; - -static inline unsigned -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) { while (first <= last) { const struct exception_table_entry *mid; @@ -21,40 +18,12 @@ search_one_table(const struct exception_table_entry *first, mid = (last - first) / 2 + first; mid_value = (unsigned long)&mid->insn + mid->insn; if (mid_value == value) - return mid->fixup.unit; + return mid; else if (mid_value < value) first = mid+1; else last = mid-1; } - return 0; -} - -unsigned -search_exception_table(unsigned long addr) -{ - unsigned ret; - -#ifndef CONFIG_MODULES - ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); -#else - extern spinlock_t modlist_lock; - unsigned long flags; - /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - - ret = 0; - spin_lock_irqsave(&modlist_lock, flags); - for (mp = module_list; mp ; mp = mp->next) { - if (!mp->ex_table_start || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) - continue; - ret = search_one_table(mp->ex_table_start, - mp->ex_table_end - 1, addr); - if (ret) - break; - } - spin_unlock_irqrestore(&modlist_lock, flags); -#endif - return ret; + return NULL; } diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 8285db87a801..d0c12c8de82e 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -24,6 +24,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -88,7 +89,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; - unsigned int fixup; + const struct exception_table_entry *fixup; int fault, si_code = SEGV_MAPERR; siginfo_t info; @@ -176,7 +177,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, no_context: /* Are we prepared to handle this fault as an exception? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { + if ((fixup = search_exception_tables(regs->pc)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); regs->pc = newpc; diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 3a2b5aaaa3b6..8e22b9bb6726 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -67,9 +67,9 @@ void module_free(struct module *module, void *region) vfree(region); } -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { return 0; diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index a81108dfb113..2fc083a98278 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -718,7 +718,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) * same format. */ -static int __init apm_driver_version(u_short *val) +static int apm_driver_version(u_short *val) { u32 eax; diff --git a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c index 2623e01b2d87..08fac292dff8 100644 --- a/arch/i386/kernel/cpu/cpufreq/elanfreq.c +++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c @@ -31,8 +31,6 @@ #define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ #define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ -#define SAFE_FREQ 33000 /* every Elan CPU can run at 33 MHz */ - static struct cpufreq_driver *elanfreq_driver; /* Module parameter */ @@ -184,7 +182,7 @@ static int elanfreq_verify (struct cpufreq_policy *policy) cpufreq_verify_within_limits(policy, 1000, max_freq); - for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--) + for (i=7; i>=0; i--) if ((elan_multiplier[i].clock >= policy->min) && (elan_multiplier[i].clock <= policy->max)) number_states++; @@ -192,57 +190,46 @@ static int elanfreq_verify (struct cpufreq_policy *policy) if (number_states) return 0; - for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--) + for (i=7; i>=0; i--) if (elan_multiplier[i].clock < policy->max) break; policy->max = elan_multiplier[i+1].clock; + cpufreq_verify_within_limits(policy, 1000, max_freq); + return 0; } static int elanfreq_setpolicy (struct cpufreq_policy *policy) { - unsigned int number_states = 0; - unsigned int i, j=4; + unsigned int i; + unsigned int optimal = 8; if (!elanfreq_driver) return -EINVAL; - for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--) - if ((elan_multiplier[i].clock >= policy->min) && - (elan_multiplier[i].clock <= policy->max)) - { - number_states++; - j = i; + for (i=0; i<8; i++) { + if ((elan_multiplier[i].clock > policy->max) || + (elan_multiplier[i].clock < policy->min)) + continue; + switch(policy->policy) { + case CPUFREQ_POLICY_POWERSAVE: + if (optimal == 8) + optimal = i; + break; + case CPUFREQ_POLICY_PERFORMANCE: + optimal = i; + break; + default: + return -EINVAL; } - - if (number_states == 1) { - elanfreq_set_cpu_state(j); - return 0; } - - switch (policy->policy) { - case CPUFREQ_POLICY_POWERSAVE: - for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--) - if ((elan_multiplier[i].clock >= policy->min) && - (elan_multiplier[i].clock <= policy->max)) - j = i; - break; - case CPUFREQ_POLICY_PERFORMANCE: - for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i++) - if ((elan_multiplier[i].clock >= policy->min) && - (elan_multiplier[i].clock <= policy->max)) - j = i; - break; - default: + if ((optimal == 8) || (elan_multiplier[optimal].clock > max_freq)) return -EINVAL; - } - if (elan_multiplier[j].clock > max_freq) - return -EINVAL; + elanfreq_set_cpu_state(optimal); - elanfreq_set_cpu_state(j); return 0; } @@ -307,7 +294,7 @@ static int __init elanfreq_init(void) driver->policy[0].max = max_freq; driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE; driver->policy[0].cpuinfo.max_freq = max_freq; - driver->policy[0].cpuinfo.min_freq = min_freq; + driver->policy[0].cpuinfo.min_freq = 1000; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; elanfreq_driver = driver; diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 52cb1a4ab188..88b88508c4e1 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -82,12 +82,17 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) /* get current state */ rdmsr(MSR_IA32_THERM_CONTROL, l, h); - l = l >> 1; - l &= 0x7; - + if (l & 0x10) { + l = l >> 1; + l &= 0x7; + } else + l = DC_DISABLE; + if (l == newstate) { set_cpus_allowed(current, cpus_allowed); return 0; + } else if (l == DC_RESV) { + printk(KERN_ERR PFX "BIG FAT WARNING: currently in invalid setting\n"); } /* notifiers */ @@ -141,13 +146,18 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) unsigned int i; unsigned int newstate = 0; unsigned int number_states = 0; + unsigned int minstate = 1; - if (!cpufreq_p4_driver || !stock_freq || !policy) + if (!cpufreq_p4_driver || !stock_freq || + !policy || !cpu_online(policy->cpu)) return -EINVAL; + if (has_N44_O17_errata) + minstate = 3; + if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { - for (i=8; i>0; i--) + for (i=8; i>=minstate; i--) if ((policy->min <= ((stock_freq / 8) * i)) && (policy->max >= ((stock_freq / 8) * i))) { @@ -155,7 +165,7 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) number_states++; } } else { - for (i=1; i<=8; i++) + for (i=minstate; i<=8; i++) if ((policy->min <= ((stock_freq / 8) * i)) && (policy->max >= ((stock_freq / 8) * i))) { @@ -164,25 +174,8 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) } } - /* if (number_states == 1) */ - { - if (policy->cpu == CPUFREQ_ALL_CPUS) { - for (i=0; i<NR_CPUS; i++) - if (cpu_online(i)) - cpufreq_p4_setdc(i, newstate); - } else { - cpufreq_p4_setdc(policy->cpu, newstate); - } - } - /* else { - if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { - min_state = newstate; - max_state = newstate + (number_states - 1); - } else { - max_state = newstate; - min_state = newstate - (number_states - 1); - } - } */ + cpufreq_p4_setdc(policy->cpu, newstate); + return 0; } @@ -190,17 +183,21 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) static int cpufreq_p4_verify(struct cpufreq_policy *policy) { unsigned int number_states = 0; - unsigned int i; + unsigned int i = 1; - if (!cpufreq_p4_driver || !stock_freq || !policy) + if (!cpufreq_p4_driver || !stock_freq || + !policy || !cpu_online(policy->cpu)) return -EINVAL; - if (!cpu_online(policy->cpu)) - policy->cpu = CPUFREQ_ALL_CPUS; - cpufreq_verify_within_limits(policy, (stock_freq / 8), stock_freq); + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + if (has_N44_O17_errata) + i = 3; - /* is there at least one state within limit? */ - for (i=1; i<=8; i++) + /* is there at least one state within the limit? */ + for (; i<=8; i++) if ((policy->min <= ((stock_freq / 8) * i)) && (policy->max >= ((stock_freq / 8) * i))) number_states++; @@ -209,11 +206,14 @@ static int cpufreq_p4_verify(struct cpufreq_policy *policy) return 0; policy->max = (stock_freq / 8) * (((unsigned int) ((policy->max * 8) / stock_freq)) + 1); + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); return 0; } -int __init cpufreq_p4_init(void) +static int __init cpufreq_p4_init(void) { struct cpuinfo_x86 *c = cpu_data; int cpuid; @@ -245,6 +245,16 @@ int __init cpufreq_p4_init(void) } printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); + + if (!stock_freq) { + if (cpu_khz) + stock_freq = cpu_khz; + else { + printk(KERN_INFO PFX "unknown core frequency - please use module parameter 'stock_freq'\n"); + return -EINVAL; + } + } + driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); if (!driver) @@ -252,9 +262,6 @@ int __init cpufreq_p4_init(void) driver->policy = (struct cpufreq_policy *) (driver + 1); - if (!stock_freq) - stock_freq = cpu_khz; - #ifdef CONFIG_CPU_FREQ_24_API for (i=0;i<NR_CPUS;i++) { driver->cpu_cur_freq[i] = stock_freq; @@ -290,15 +297,16 @@ int __init cpufreq_p4_init(void) } -void __exit cpufreq_p4_exit(void) +static void __exit cpufreq_p4_exit(void) { - u32 l, h; + unsigned int i; if (cpufreq_p4_driver) { + for (i=0; i<NR_CPUS; i++) { + if (cpu_online(i)) + cpufreq_p4_setdc(i, DC_DISABLE); + } cpufreq_unregister(); - /* return back to a non modulated state */ - rdmsr(MSR_IA32_THERM_CONTROL, l, h); - wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); kfree(cpufreq_p4_driver); } } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 5da9aae308d6..198def807850 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -253,11 +253,11 @@ ENTRY(sysenter_entry) * Careful about security. */ cmpl $__PAGE_OFFSET-3,%ebp - jae syscall_badsys + jae syscall_fault 1: movl (%ebp),%ebp .section __ex_table,"a" .align 4 - .long 1b,syscall_badsys + .long 1b,syscall_fault .previous pushl %eax @@ -367,6 +367,14 @@ syscall_exit_work: jmp resume_userspace ALIGN +syscall_fault: + pushl %eax # save orig_eax + SAVE_ALL + GET_THREAD_INFO(%ebx) + movl $-EFAULT,EAX(%esp) + jmp resume_userspace + + ALIGN syscall_badsys: movl $-ENOSYS,EAX(%esp) jmp resume_userspace diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index a795bafc6f17..fcaa3693e115 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -124,6 +124,6 @@ asmlinkage int sys_iopl(unsigned long unused) } regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); /* Make sure we return the long way (not sysenter) */ - set_thread_flag(TIF_SIGPENDING); + set_thread_flag(TIF_IRET); return 0; } diff --git a/arch/i386/kernel/module.c b/arch/i386/kernel/module.c index d71b0e367eb6..d92e448a2c8c 100644 --- a/arch/i386/kernel/module.c +++ b/arch/i386/kernel/module.c @@ -45,9 +45,9 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { return 0; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index c6108fa910e1..fbcfc1f2c2bd 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -555,7 +555,7 @@ asmlinkage int sys_execve(struct pt_regs regs) if (error == 0) { current->ptrace &= ~PT_DTRACE; /* Make sure we don't return using sysenter.. */ - set_thread_flag(TIF_SIGPENDING); + set_thread_flag(TIF_IRET); } putname(filename); out: diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 444e1c24a808..1c17237fe978 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -617,4 +617,6 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs,oldset); + + clear_thread_flag(TIF_IRET); } diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index 2f84d4172cd8..4e56b5f99a60 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -189,39 +189,38 @@ bad_ctc: #ifdef CONFIG_CPU_FREQ +static unsigned int ref_freq = 0; +static unsigned long loops_per_jiffy_ref = 0; + +#ifndef CONFIG_SMP +static unsigned long fast_gettimeoffset_ref = 0; +static unsigned long cpu_khz_ref = 0; +#endif static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; - unsigned int i; - if (!cpu_has_tsc) - return 0; + if (!ref_freq) { + ref_freq = freq->old; + loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; +#ifndef CONFIG_SMP + fast_gettimeoffset_ref = fast_gettimeoffset_quotient; + cpu_khz_ref = cpu_khz; +#endif + } - switch (val) { - case CPUFREQ_PRECHANGE: - if ((freq->old < freq->new) && - ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0))) { - cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new); - fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old); - } - for (i=0; i<NR_CPUS; i++) - if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i)) - cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new); - break; - - case CPUFREQ_POSTCHANGE: - if ((freq->new < freq->old) && - ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0))) { - cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new); - fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old); + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); +#ifndef CONFIG_SMP + if (use_tsc) { + fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq); + cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); } - for (i=0; i<NR_CPUS; i++) - if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i)) - cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new); - break; +#endif } return 0; @@ -260,6 +259,10 @@ static int init_tsc(void) * moaned if you have the only one in the world - you fix it! */ +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +#endif + if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); if (tsc_quotient) { @@ -282,9 +285,6 @@ static int init_tsc(void) "0" (eax), "1" (edx)); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } -#ifdef CONFIG_CPU_FREQ - cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -#endif return 0; } } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index c028ac4ab667..332ccea33b8b 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -87,50 +87,6 @@ asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; - -/* - * If the address is either in the .text section of the - * kernel, or in the vmalloc'ed module regions, it *may* - * be the address of a calling routine - */ - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - int retval = 0; - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void *)addr, 0, mod)) { - retval = 1; - break; - } - } - - return retval; -} - -#else - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif - void show_trace(unsigned long * stack) { int i; @@ -338,7 +294,7 @@ static inline void do_trap(int trapnr, int signr, char *str, int vm86, } kernel_trap: { - unsigned long fixup; + const struct exception_table_entry *fixup; #ifdef CONFIG_PNPBIOS if (unlikely((regs->xcs | 8) == 0x88)) /* 0x80 or 0x88 */ { @@ -354,9 +310,9 @@ static inline void do_trap(int trapnr, int signr, char *str, int vm86, } #endif - fixup = search_exception_table(regs->eip); + fixup = search_exception_tables(regs->eip); if (fixup) - regs->eip = fixup; + regs->eip = fixup->fixup; else die(str, regs, error_code); return; @@ -435,10 +391,10 @@ gp_in_vm86: gp_in_kernel: { - unsigned long fixup; - fixup = search_exception_table(regs->eip); + const struct exception_table_entry *fixup; + fixup = search_exception_tables(regs->eip); if (fixup) { - regs->eip = fixup; + regs->eip = fixup->fixup; return; } die("general protection fault", regs, error_code); diff --git a/arch/i386/mm/extable.c b/arch/i386/mm/extable.c index b94fb8d234da..946e7ad6fbcb 100644 --- a/arch/i386/mm/extable.c +++ b/arch/i386/mm/extable.c @@ -7,13 +7,11 @@ #include <linux/spinlock.h> #include <asm/uaccess.h> -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; - -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) { while (first <= last) { const struct exception_table_entry *mid; @@ -22,43 +20,11 @@ search_one_table(const struct exception_table_entry *first, mid = (last - first) / 2 + first; diff = mid->insn - value; if (diff == 0) - return mid->fixup; + return mid; else if (diff < 0) first = mid+1; else last = mid-1; } - return 0; -} - -extern spinlock_t modlist_lock; - -unsigned long -search_exception_table(unsigned long addr) -{ - unsigned long ret = 0; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - return ret; -#else - unsigned long flags; - struct list_head *i; - - /* The kernel is the last "module" -- no need to treat it special. */ - spin_lock_irqsave(&modlist_lock, flags); - list_for_each(i, &extables) { - struct exception_table *ex - = list_entry(i, struct exception_table, list); - if (ex->num_entries == 0) - continue; - ret = search_one_table(ex->entry, - ex->entry + ex->num_entries - 1, addr); - if (ret) - break; - } - spin_unlock_irqrestore(&modlist_lock, flags); - return ret; -#endif + return NULL; } diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 56827d817963..e1ebd7239849 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ +#include <linux/module.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -154,7 +155,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) struct vm_area_struct * vma; unsigned long address; unsigned long page; - unsigned long fixup; + const struct exception_table_entry *fixup; int write; siginfo_t info; @@ -310,8 +311,8 @@ bad_area: no_context: /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->eip)) != 0) { - regs->eip = fixup; + if ((fixup = search_exception_tables(regs->eip)) != NULL) { + regs->eip = fixup->fixup; return; } diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 14a61a9bf5c4..1663e7730a18 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -234,8 +234,12 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) ret = -ENOMEM; goto out; } - add_to_page_cache(page, mapping, idx); + ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); unlock_page(page); + if (ret) { + free_huge_page(page); + goto out; + } } set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 8d1e2c1e5148..0d33b4830d84 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -438,6 +438,16 @@ void __init mem_init(void) bad_ppro = ppro_with_ram_bug(); +#ifdef CONFIG_HIGHMEM + /* check that fixmap and pkmap do not overlap */ + if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) { + printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n"); + printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n", + PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START); + BUG(); + } +#endif + set_max_mapnr_init(); #ifdef CONFIG_HIGHMEM diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index ad20bedba50c..65860c3865a5 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -821,42 +821,6 @@ asmlinkage void buserr_c(struct frame *fp) static int kstack_depth_to_print = 48; -extern char _stext, _etext; - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void *)addr, 0, mod)) - return 1; - } - - return 0; -} - -#else // !CONFIG_MODULES - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif // !CONFIG_MODULES - void show_trace(unsigned long *stack) { unsigned long *endstack; diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c index 0437fc375d0c..a7672504939b 100644 --- a/arch/mips/kernel/pci.c +++ b/arch/mips/kernel/pci.c @@ -3,7 +3,7 @@ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * Modified to be mips generic, ppopov@mvista.com - * arch/mips/kernl/pci.c + * arch/mips/kernel/pci.c * Common MIPS PCI routines. * * This program is free software; you can redistribute it and/or modify it diff --git a/arch/mips64/sgi-ip27/ip27-rtc.c b/arch/mips64/sgi-ip27/ip27-rtc.c index 3a71a4b8b2fd..084d341a8b5b 100644 --- a/arch/mips64/sgi-ip27/ip27-rtc.c +++ b/arch/mips64/sgi-ip27/ip27-rtc.c @@ -202,9 +202,15 @@ static int __init rtc_init(void) KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0; printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); - if (misc_register(&rtc_dev)) + if (misc_register(&rtc_dev)) { + printk(KERN_ERR "rtc: cannot register misc device.\n"); return -ENODEV; - create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL); + } + if (!create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL)) { + printk(KERN_ERR "rtc: cannot create /proc/rtc.\n"); + misc_deregister(&rtc_dev); + return -ENOENT; + } save_flags(flags); cli(); diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index e597f1478e46..e8544761df0a 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -500,6 +500,8 @@ static struct miscdevice perf_dev = { */ static int __init perf_init(void) { + int retval; + /* Determine correct processor interface to use */ bitmask_array = perf_bitmasks; @@ -518,11 +520,17 @@ static int __init perf_init(void) return -ENODEV; } + retval = misc_register(&perf_dev); + if (retval < 0) { + printk(KERN_ERR "Performance monitoring counters: " + "cannot register misc device.\n"); + return retval; + } + /* Patch the images to match the system */ perf_patch_images(); spin_lock_init(&perf_lock); - misc_register(&perf_dev); /* TODO: this only lets us access the first cpu.. what to do for SMP? */ cpu_device = cpu_data[0].dev; diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index f108dbc1614e..ed250fadcd89 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -123,31 +123,6 @@ void dump_stack(void) static int kstack_depth_to_print = 48; -extern struct module kernel_module; - -static inline int kernel_text_address(unsigned long addr) -{ -#ifdef CONFIG_MODULES - struct module *mod; -#endif - extern char _stext, _etext; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - -#ifdef CONFIG_MODULES - for (mod = module_list; mod != &kernel_module; mod = mod->next) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound(addr, 0, mod)) - return 1; - } -#endif - - return 0; -} void show_stack(unsigned long *sp) { diff --git a/arch/ppc/kernel/module.c b/arch/ppc/kernel/module.c index 696a4faaeb3c..639b07c008ba 100644 --- a/arch/ppc/kernel/module.c +++ b/arch/ppc/kernel/module.c @@ -103,7 +103,7 @@ static unsigned long get_plt_size(const Elf32_Ehdr *hdr, int module_frob_arch_sections(Elf32_Ehdr *hdr, Elf32_Shdr *sechdrs, - const char *secstrings, + char *secstrings, struct module *me) { unsigned int i; diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 16a8128d5aaa..9d4fc78b2dc9 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -29,6 +29,7 @@ #include <linux/interrupt.h> #include <linux/config.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/pgtable.h> #include <asm/uaccess.h> @@ -115,7 +116,7 @@ void MachineCheckException(struct pt_regs *regs) { #ifdef CONFIG_ALL_PPC - unsigned long fixup; + const struct exception_table_entry *entry; #endif /* CONFIG_ALL_PPC */ unsigned long msr = regs->msr; @@ -148,7 +149,7 @@ MachineCheckException(struct pt_regs *regs) * -- paulus. */ if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000))) - && (fixup = search_exception_table(regs->nip)) != 0) { + && (entry = search_exception_tables(regs->nip)) != NULL) { /* * Check that it's a sync instruction, or somewhere * in the twi; isync; nop sequence that inb/inw/inl uses. diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c index aee3118d18d2..3b8f08b47ab3 100644 --- a/arch/ppc/mm/extable.c +++ b/arch/ppc/mm/extable.c @@ -6,6 +6,7 @@ #include <linux/config.h> #include <linux/module.h> +#include <linux/init.h> #include <asm/uaccess.h> extern struct exception_table_entry __start___ex_table[]; @@ -40,16 +41,17 @@ sort_ex_table(struct exception_table_entry *start, } } -void +void __init sort_exception_table(void) { sort_ex_table(__start___ex_table, __stop___ex_table); } -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) { while (first <= last) { const struct exception_table_entry *mid; @@ -58,41 +60,11 @@ search_one_table(const struct exception_table_entry *first, mid = (last - first) / 2 + first; diff = mid->insn - value; if (diff == 0) - return mid->fixup; + return mid; else if (diff < 0) first = mid+1; else last = mid-1; } - return 0; -} - -unsigned long -search_exception_table(unsigned long addr) -{ - unsigned long ret = 0; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); -#else - unsigned long flags; - struct list_head *i; - - /* The kernel is the last "module" -- no need to treat it special. */ - spin_lock_irqsave(&modlist_lock, flags); - list_for_each(i, &extables) { - struct exception_table *ex - = list_entry(i, struct exception_table, list); - if (ex->num_entries == 0) - continue; - ret = search_one_table(ex->entry, - ex->entry + ex->num_entries - 1, addr); - if (ret) - break; - } - spin_unlock_irqrestore(&modlist_lock, flags); -#endif - - return ret; + return NULL; } diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index de7d090e7b47..686745055096 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/highmem.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -263,12 +264,11 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) { extern void die(const char *,struct pt_regs *,long); - - unsigned long fixup; + const struct exception_table_entry *entry; /* Are we prepared to handle this fault? */ - if ((fixup = search_exception_table(regs->nip)) != 0) { - regs->nip = fixup; + if ((entry = search_exception_tables(regs->nip)) != NULL) { + regs->nip = entry->fixup; return; } diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 4dce1e9e74f2..20e1d2bc0e2d 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -196,8 +196,17 @@ static struct miscdevice rtc_dev= static int __init rtc_init(void) { - misc_register(&rtc_dev); - create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + int retval; + + retval = misc_register(&rtc_dev); + if(retval < 0) + return retval; + +#ifdef CONFIG_PROC_FS + if(create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL) == NULL) + misc_deregister(&rtc_dev); + return -ENOMEM; +#endif printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n"); diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index ef722cd2058f..1898fd9aeaa4 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -57,7 +57,7 @@ struct sigregs32 { /* * the gp_regs array is 32 bit representation of the pt_regs - * structure that was stored on the kernle stack during the + * structure that was stored on the kernel stack during the * system call that was interrupted for the signal. * * Note that the entire pt_regs regs structure will fit in diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index d1d4dd05c212..537a5e802070 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -51,9 +51,9 @@ void module_free(struct module *mod, void *module_region) table entries. */ } -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { // FIXME: add space needed for GOT/PLT diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 5eb5923e001b..8706fc762fd7 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -63,50 +63,6 @@ static ext_int_info_t ext_int_pfault; static int kstack_depth_to_print = 12; -/* - * If the address is either in the .text section of the - * kernel, or in the vmalloc'ed module regions, it *may* - * be the address of a calling routine - */ -extern char _stext, _etext; - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - int retval = 0; - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void*)addr, 0, mod)) { - retval = 1; - break; - } - } - - return retval; -} - -#else - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif - void show_trace(unsigned long * stack) { unsigned long backchain, low_addr, high_addr, ret_addr; diff --git a/arch/s390x/kernel/module.c b/arch/s390x/kernel/module.c index 61f3b34e90be..f35512379467 100644 --- a/arch/s390x/kernel/module.c +++ b/arch/s390x/kernel/module.c @@ -52,9 +52,9 @@ void module_free(struct module *mod, void *module_region) } /* s390/s390x needs additional memory for GOT/PLT sections. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { // FIXME: add space needed for GOT/PLT diff --git a/arch/s390x/kernel/traps.c b/arch/s390x/kernel/traps.c index e67855f55ac4..1c5cd64b3ecd 100644 --- a/arch/s390x/kernel/traps.c +++ b/arch/s390x/kernel/traps.c @@ -65,50 +65,6 @@ static ext_int_info_t ext_int_pfault; static int kstack_depth_to_print = 20; -/* - * If the address is either in the .text section of the - * kernel, or in the vmalloc'ed module regions, it *may* - * be the address of a calling routine - */ -extern char _stext, _etext; - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - int retval = 0; - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void*)addr, 0, mod)) { - retval = 1; - break; - } - } - - return retval; -} - -#else - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif - void show_trace(unsigned long * stack) { unsigned long backchain, low_addr, high_addr, ret_addr; diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 348c24f63d85..26aa5e1259d4 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -37,9 +37,9 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { return 0; diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index f6107871dfd3..035c7bf4232a 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -450,13 +450,13 @@ struct ifreq32 { struct ifmap32 ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; - __kernel_caddr_t32 ifru_data; + compat_caddr_t ifru_data; } ifr_ifru; }; struct ifconf32 { int ifc_len; /* size of buffer */ - __kernel_caddr_t32 ifcbuf; + compat_caddr_t ifcbuf; }; #ifdef CONFIG_NET @@ -1009,7 +1009,7 @@ static int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg) struct fb_fix_screeninfo32 { char id[16]; - __kernel_caddr_t32 smem_start; + compat_caddr_t smem_start; __u32 smem_len; __u32 type; __u32 type_aux; @@ -1018,7 +1018,7 @@ struct fb_fix_screeninfo32 { __u16 ypanstep; __u16 ywrapstep; __u32 line_length; - __kernel_caddr_t32 mmio_start; + compat_caddr_t mmio_start; __u32 mmio_len; __u32 accel; __u16 reserved[3]; @@ -1027,10 +1027,10 @@ struct fb_fix_screeninfo32 { struct fb_cmap32 { __u32 start; __u32 len; - __kernel_caddr_t32 red; - __kernel_caddr_t32 green; - __kernel_caddr_t32 blue; - __kernel_caddr_t32 transp; + compat_caddr_t red; + compat_caddr_t green; + compat_caddr_t blue; + compat_caddr_t transp; }; static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -1169,7 +1169,7 @@ struct floppy_struct32 { unsigned char rate; unsigned char spec1; unsigned char fmt_gap; - const __kernel_caddr_t32 name; + const compat_caddr_t name; }; struct floppy_drive_params32 { @@ -1208,7 +1208,7 @@ struct floppy_drive_struct32 { int fd_ref; int fd_device; int last_checked; - __kernel_caddr_t32 dmabuf; + compat_caddr_t dmabuf; int bufblocks; }; @@ -1732,7 +1732,7 @@ static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigne } struct ppp_option_data32 { - __kernel_caddr_t32 ptr; + compat_caddr_t ptr; __u32 length; int transmit; }; @@ -1813,8 +1813,8 @@ struct mtget32 { __u32 mt_dsreg; __u32 mt_gstat; __u32 mt_erreg; - __kernel_daddr_t32 mt_fileno; - __kernel_daddr_t32 mt_blkno; + compat_daddr_t mt_fileno; + compat_daddr_t mt_blkno; }; #define MTIOCGET32 _IOR('m', 2, struct mtget32) @@ -1932,7 +1932,7 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) struct cdrom_read32 { int cdread_lba; - __kernel_caddr_t32 cdread_bufaddr; + compat_caddr_t cdread_bufaddr; int cdread_buflen; }; @@ -1940,16 +1940,16 @@ struct cdrom_read_audio32 { union cdrom_addr addr; u_char addr_format; int nframes; - __kernel_caddr_t32 buf; + compat_caddr_t buf; }; struct cdrom_generic_command32 { unsigned char cmd[CDROM_PACKET_SIZE]; - __kernel_caddr_t32 buffer; + compat_caddr_t buffer; unsigned int buflen; int stat; - __kernel_caddr_t32 sense; - __kernel_caddr_t32 reserved[3]; + compat_caddr_t sense; + compat_caddr_t reserved[3]; }; static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -1958,7 +1958,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar struct cdrom_read cdread; struct cdrom_read_audio cdreadaudio; struct cdrom_generic_command cgc; - __kernel_caddr_t32 addr; + compat_caddr_t addr; char *data = 0; void *karg; int err = 0; @@ -2041,9 +2041,9 @@ out: if (data) struct loop_info32 { int lo_number; /* ioctl r/o */ - __kernel_dev_t32 lo_device; /* ioctl r/o */ + compat_dev_t lo_device; /* ioctl r/o */ unsigned int lo_inode; /* ioctl r/o */ - __kernel_dev_t32 lo_rdevice; /* ioctl r/o */ + compat_dev_t lo_rdevice; /* ioctl r/o */ int lo_offset; int lo_encrypt_type; int lo_encrypt_key_size; /* ioctl w/o */ @@ -2248,7 +2248,7 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a set_fs(old_fs); if (err >= 0) - err = put_user(kuid, (__kernel_uid_t32 *)arg); + err = put_user(kuid, (compat_uid_t *)arg); return err; } @@ -2256,7 +2256,7 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a struct ncp_ioctl_request_32 { unsigned int function; unsigned int size; - __kernel_caddr_t32 data; + compat_caddr_t data; }; struct ncp_fs_info_v2_32 { @@ -2277,13 +2277,13 @@ struct ncp_objectname_ioctl_32 { int auth_type; unsigned int object_name_len; - __kernel_caddr_t32 object_name; /* an userspace data, in most cases user name */ + compat_caddr_t object_name; /* an userspace data, in most cases user name */ }; struct ncp_privatedata_ioctl_32 { unsigned int len; - __kernel_caddr_t32 data; /* ~1000 for NDS */ + compat_caddr_t data; /* ~1000 for NDS */ }; #define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct ncp_ioctl_request_32) @@ -2557,12 +2557,12 @@ static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned lon struct atmif_sioc32 { int number; int length; - __kernel_caddr_t32 arg; + compat_caddr_t arg; }; struct atm_iobuf32 { int length; - __kernel_caddr_t32 buffer; + compat_caddr_t buffer; }; #define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) @@ -2623,7 +2623,7 @@ static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) iobuf.length = iobuf32.length; - if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) { + if (iobuf32.buffer == (compat_caddr_t) NULL || iobuf32.length == 0) { iobuf.buffer = (void*)(unsigned long)iobuf32.buffer; } else { iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL); @@ -2677,7 +2677,7 @@ static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) sioc.number = sioc32.number; sioc.length = sioc32.length; - if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) { + if (sioc32.arg == (compat_caddr_t) NULL || sioc32.length == 0) { sioc.arg = (void*)(unsigned long)sioc32.arg; } else { sioc.arg = kmalloc(sioc.length, GFP_KERNEL); @@ -2835,7 +2835,7 @@ typedef struct { } lv_status_byindex_req32_t; typedef struct { - __kernel_dev_t32 dev; + compat_dev_t dev; u32 lv; } lv_status_bydev_req32_t; @@ -5128,7 +5128,7 @@ HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) /* One SMB ioctl needs translations. */ -#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32) +#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) /* NCPFS */ HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest) diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c index dc0daa59aac1..cf6aa58b9564 100644 --- a/arch/sparc64/kernel/module.c +++ b/arch/sparc64/kernel/module.c @@ -144,9 +144,9 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { return 0; diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c index bcfa77a396bf..c95f15885c18 100644 --- a/arch/sparc64/kernel/sunos_ioctl32.c +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -22,6 +22,7 @@ #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/compat.h> #include <asm/kbio.h> /* Use this to get at 32-bit user passed pointers. */ @@ -80,13 +81,13 @@ struct ifreq32 { int ifru_mtu; struct ifmap32 ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - __kernel_caddr_t32 ifru_data; + compat_caddr_t ifru_data; } ifr_ifru; }; struct ifconf32 { int ifc_len; /* size of buffer */ - __kernel_caddr_t32 ifcbuf; + compat_caddr_t ifcbuf; }; extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index e22bbcc94a97..d18415e983c9 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -290,11 +290,11 @@ struct msgbuf32 { s32 mtype; char mtext[1]; }; struct ipc_perm32 { key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; - __kernel_mode_t32 mode; + compat_uid_t uid; + compat_gid_t gid; + compat_uid_t cuid; + compat_gid_t cgid; + compat_mode_t mode; unsigned short seq; }; @@ -333,8 +333,8 @@ struct msqid_ds32 unsigned short msg_cbytes; unsigned short msg_qnum; unsigned short msg_qbytes; - __kernel_ipc_pid_t32 msg_lspid; - __kernel_ipc_pid_t32 msg_lrpid; + compat_ipc_pid_t msg_lspid; + compat_ipc_pid_t msg_lrpid; }; struct msqid64_ds32 { @@ -348,8 +348,8 @@ struct msqid64_ds32 { unsigned int msg_cbytes; unsigned int msg_qnum; unsigned int msg_qbytes; - __kernel_pid_t32 msg_lspid; - __kernel_pid_t32 msg_lrpid; + compat_pid_t msg_lspid; + compat_pid_t msg_lrpid; unsigned int __unused1; unsigned int __unused2; }; @@ -361,8 +361,8 @@ struct shmid_ds32 { compat_time_t shm_atime; compat_time_t shm_dtime; compat_time_t shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; + compat_ipc_pid_t shm_cpid; + compat_ipc_pid_t shm_lpid; unsigned short shm_nattch; }; @@ -375,8 +375,8 @@ struct shmid64_ds32 { unsigned int __pad3; compat_time_t shm_ctime; compat_size_t shm_segsz; - __kernel_pid_t32 shm_cpid; - __kernel_pid_t32 shm_lpid; + compat_pid_t shm_cpid; + compat_pid_t shm_lpid; unsigned int shm_nattch; unsigned int __unused1; unsigned int __unused2; @@ -1378,6 +1378,9 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf) { int err; + if (stat->size > MAX_NON_LFS) + return -EOVERFLOW; + err = put_user(stat->dev, &statbuf->st_dev); err |= put_user(stat->ino, &statbuf->st_ino); err |= put_user(stat->mode, &statbuf->st_mode); @@ -1385,8 +1388,6 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf) err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid); err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid); err |= put_user(stat->rdev, &statbuf->st_rdev); - if (stat->size > MAX_NON_LFS) - return -EOVERFLOW; err |= put_user(stat->size, &statbuf->st_size); err |= put_user(stat->atime.tv_sec, &statbuf->st_atime); err |= put_user(0, &statbuf->__unused1); @@ -1412,16 +1413,16 @@ asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2) struct ncp_mount_data32_v3 { int version; unsigned int ncp_fd; - __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; + compat_uid_t mounted_uid; + compat_pid_t wdog_pid; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; unsigned int time_out; unsigned int retry_count; unsigned int flags; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + compat_uid_t uid; + compat_gid_t gid; + compat_mode_t file_mode; + compat_mode_t dir_mode; }; struct ncp_mount_data32_v4 { @@ -1492,11 +1493,11 @@ static void *do_ncp_super_data_conv(void *raw_data) struct smb_mount_data32 { int version; - __kernel_uid_t32 mounted_uid; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; + compat_uid_t mounted_uid; + compat_uid_t uid; + compat_gid_t gid; + compat_mode_t file_mode; + compat_mode_t dir_mode; }; static void *do_smb_super_data_conv(void *raw_data) @@ -1656,7 +1657,7 @@ static int put_rusage (struct rusage32 *ru, struct rusage *r) return err; } -asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru) +asmlinkage int sys32_wait4(compat_pid_t pid, unsigned int *stat_addr, int options, struct rusage32 *ru) { if (!ru) return sys_wait4(pid, stat_addr, options, NULL); @@ -1718,7 +1719,7 @@ asmlinkage int sys32_sysinfo(struct sysinfo32 *info) extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); -asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct compat_timespec *interval) +asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec *interval) { struct timespec t; int ret; @@ -3027,27 +3028,27 @@ struct nfsctl_client32 { struct nfsctl_export32 { s8 ex32_client[NFSCLNT_IDMAX+1]; s8 ex32_path[NFS_MAXPATHLEN+1]; - __kernel_dev_t32 ex32_dev; - __kernel_ino_t32 ex32_ino; + compat_dev_t ex32_dev; + compat_ino_t ex32_ino; s32 ex32_flags; - __kernel_uid_t32 ex32_anon_uid; - __kernel_gid_t32 ex32_anon_gid; + compat_uid_t ex32_anon_uid; + compat_gid_t ex32_anon_gid; }; struct nfsctl_uidmap32 { u32 ug32_ident; /* char * */ - __kernel_uid_t32 ug32_uidbase; + compat_uid_t ug32_uidbase; s32 ug32_uidlen; u32 ug32_udimap; /* uid_t * */ - __kernel_uid_t32 ug32_gidbase; + compat_uid_t ug32_gidbase; s32 ug32_gidlen; u32 ug32_gdimap; /* gid_t * */ }; struct nfsctl_fhparm32 { struct sockaddr gf32_addr; - __kernel_dev_t32 gf32_dev; - __kernel_ino_t32 gf32_ino; + compat_dev_t gf32_dev; + compat_ino_t gf32_ino; s32 gf32_version; }; @@ -3176,7 +3177,7 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_uidlen; i++) err |= __get_user(karg->ca_umap.ug_udimap[i], - &(((__kernel_uid_t32 *)A(uaddr))[i])); + &(((compat_uid_t *)A(uaddr))[i])); err |= __get_user(karg->ca_umap.ug_gidbase, &arg32->ca32_umap.ug32_gidbase); err |= __get_user(karg->ca_umap.ug_uidlen, @@ -3190,7 +3191,7 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_gidlen; i++) err |= __get_user(karg->ca_umap.ug_gdimap[i], - &(((__kernel_gid_t32 *)A(uaddr))[i])); + &(((compat_gid_t *)A(uaddr))[i])); return (err ? -EFAULT : 0); } @@ -3482,7 +3483,7 @@ asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 coun extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); -asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) +asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -3503,7 +3504,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count); -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count) +asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; @@ -3737,7 +3738,7 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) extern asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr); -asmlinkage int sys32_sched_setaffinity(__kernel_pid_t32 pid, unsigned int len, +asmlinkage int sys32_sched_setaffinity(compat_pid_t pid, unsigned int len, u32 *user_mask_ptr) { unsigned long kernel_mask; @@ -3761,7 +3762,7 @@ asmlinkage int sys32_sched_setaffinity(__kernel_pid_t32 pid, unsigned int len, extern asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr); -asmlinkage int sys32_sched_getaffinity(__kernel_pid_t32 pid, unsigned int len, +asmlinkage int sys32_sched_getaffinity(compat_pid_t pid, unsigned int len, u32 *user_mask_ptr) { unsigned long kernel_mask; diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index cb27fd8fb5aa..3fae734358c5 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -798,14 +798,14 @@ asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) } /* So stupid... */ -extern asmlinkage int sys32_wait4(__kernel_pid_t32 pid, +extern asmlinkage int sys32_wait4(compat_pid_t pid, u32 stat_addr, int options, u32 ru); -asmlinkage int sunos_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru) +asmlinkage int sunos_wait4(compat_pid_t pid, u32 stat_addr, int options, u32 ru) { int ret; - ret = sys32_wait4((pid ? pid : ((__kernel_pid_t32)-1)), + ret = sys32_wait4((pid ? pid : ((compat_pid_t)-1)), stat_addr, options, ru); return ret; } @@ -931,11 +931,11 @@ struct msgbuf32 { struct ipc_perm32 { key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; - __kernel_mode_t32 mode; + compat_uid_t uid; + compat_gid_t gid; + compat_uid_t cuid; + compat_gid_t cgid; + compat_mode_t mode; unsigned short seq; }; @@ -952,8 +952,8 @@ struct msqid_ds32 unsigned short msg_cbytes; unsigned short msg_qnum; unsigned short msg_qbytes; - __kernel_ipc_pid_t32 msg_lspid; - __kernel_ipc_pid_t32 msg_lrpid; + compat_ipc_pid_t msg_lspid; + compat_ipc_pid_t msg_lrpid; }; static inline int sunos_msqid_get(struct msqid_ds32 *user, @@ -1084,8 +1084,8 @@ struct shmid_ds32 { compat_time_t shm_atime; compat_time_t shm_dtime; compat_time_t shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; + compat_ipc_pid_t shm_cpid; + compat_ipc_pid_t shm_lpid; unsigned short shm_nattch; }; diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 6c0db000fcf1..23e5a862f088 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -149,10 +149,10 @@ void data_access_exception (struct pt_regs *regs, if (regs->tstate & TSTATE_PRIV) { /* Test if this comes from uaccess places. */ - unsigned long fixup, g2; + unsigned long fixup; + unsigned long g2 = regs->u_regs[UREG_G2]; - g2 = regs->u_regs[UREG_G2]; - if ((fixup = search_exception_table (regs->tpc, &g2))) { + if ((fixup = search_extables_range(regs->tpc, &g2))) { /* Ouch, somebody is trying ugly VM hole tricks on us... */ #ifdef DEBUG_EXCEPTIONS printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); @@ -1370,7 +1370,7 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned recoverable = 1; } else { unsigned long g2 = regs->u_regs[UREG_G2]; - unsigned long fixup = search_exception_table(regs->tpc, &g2); + unsigned long fixup = search_extables_range(regs->tpc, &g2); if (fixup != 0UL) { /* OK, kernel access to userspace. */ @@ -1390,7 +1390,7 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned /* Only perform fixup if we still have a * recoverable condition. */ - if (fixup != 0UL && recoverable) { + if (recoverable) { regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs[UREG_G2] = g2; diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index d5f8f8eb0360..1d403a089e01 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/module.h> #include <asm/asi.h> #include <asm/ptrace.h> #include <asm/pstate.h> @@ -360,7 +361,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("ke void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) { unsigned long g2 = regs->u_regs [UREG_G2]; - unsigned long fixup = search_exception_table (regs->tpc, &g2); + unsigned long fixup = search_extables_range(regs->tpc, &g2); if (!fixup) { unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); diff --git a/arch/sparc64/mm/extable.c b/arch/sparc64/mm/extable.c index 638a68166332..54a17bc63324 100644 --- a/arch/sparc64/mm/extable.c +++ b/arch/sparc64/mm/extable.c @@ -9,10 +9,11 @@ extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; -static unsigned long -search_one_table(const struct exception_table_entry *start, - const struct exception_table_entry *end, - unsigned long value, unsigned long *g2) +/* Caller knows they are in a range if ret->fixup == 0 */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *start, + const struct exception_table_entry *last, + unsigned long value) { const struct exception_table_entry *walk; @@ -30,7 +31,7 @@ search_one_table(const struct exception_table_entry *start, */ /* 1. Try to find an exact match. */ - for (walk = start; walk <= end; walk++) { + for (walk = start; walk <= last; walk++) { if (walk->fixup == 0) { /* A range entry, skip both parts. */ walk++; @@ -38,55 +39,37 @@ search_one_table(const struct exception_table_entry *start, } if (walk->insn == value) - return walk->fixup; + return walk; } /* 2. Try to find a range match. */ - for (walk = start; walk <= (end - 1); walk++) { + for (walk = start; walk <= (last - 1); walk++) { if (walk->fixup) continue; - if (walk[0].insn <= value && - walk[1].insn > value) { - *g2 = (value - walk[0].insn) / 4; - return walk[1].fixup; - } + if (walk[0].insn <= value && walk[1].insn > value) + return walk; + walk++; } - return 0; + return NULL; } -extern spinlock_t modlist_lock; - -unsigned long -search_exception_table(unsigned long addr, unsigned long *g2) +/* Special extable search, which handles ranges. Returns fixup */ +unsigned long search_extables_range(unsigned long addr, unsigned long *g2) { - unsigned long ret = 0; + const struct exception_table_entry *entry; -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - ret = search_one_table(__start___ex_table, - __stop___ex_table-1, addr, g2); - return ret; -#else - unsigned long flags; - struct list_head *i; + entry = search_exception_tables(addr); + if (!entry) + return 0; - /* The kernel is the last "module" -- no need to treat it special. */ - spin_lock_irqsave(&modlist_lock, flags); - list_for_each(i, &extables) { - struct exception_table *ex = - list_entry(i, struct exception_table, list); - if (ex->num_entries == 0) - continue; - ret = search_one_table(ex->entry, - ex->entry + ex->num_entries - 1, - addr, g2); - if (ret) - break; + /* Inside range? Fix g2 and return correct fixup */ + if (!entry->fixup) { + *g2 = (addr - entry->insn) / 4; + return (entry + 1)->fixup; } - spin_unlock_irqrestore(&modlist_lock, flags); - return ret; -#endif + + return entry->fixup; } diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index e5aa61b9f52d..5c4a56023668 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -14,6 +14,7 @@ #include <linux/mman.h> #include <linux/signal.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -285,7 +286,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, /* Look in asi.h: All _S asis have LS bit set */ if ((asi & 0x1) && - (fixup = search_exception_table (regs->tpc, &g2))) { + (fixup = search_extables_range(regs->tpc, &g2))) { regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs[UREG_G2] = g2; diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index e48dbcb2c497..98045169d9c1 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -476,9 +476,16 @@ try_again: page = alloc_hugetlb_page(); if (page == NULL) { pte_unmap(pte); + retval = -ENOMEM; + goto out; + } + retval = add_to_page_cache(page, mapping, + idx, GFP_ATOMIC); + if (retval) { + pte_unmap(pte); + free_hugetlb_page(page); goto out; } - add_to_page_cache(page, mapping, idx); } set_huge_pte(mm, vma, page, pte, (vma->vm_flags & VM_WRITE)); diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 2bf29ad7ad27..4936445793b7 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -11,49 +11,6 @@ #include "sysrq.h" #include "user_util.h" - /* - * If the address is either in the .text section of the - * kernel, or in the vmalloc'ed module regions, it *may* - * be the address of a calling routine - */ - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - int retval = 0; - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void *) addr, 0, mod)) { - retval = 1; - break; - } - } - - return retval; -} - -#else - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif - void show_trace(unsigned long * stack) { int i; diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c index c585076087db..9331fa3cda4d 100644 --- a/arch/x86_64/kernel/module.c +++ b/arch/x86_64/kernel/module.c @@ -26,9 +26,9 @@ #define DEBUGP(fmt...) /* We don't need anything special. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) { return 0; diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 20c4811bad6b..af118388f169 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -104,44 +104,6 @@ int printk_address(unsigned long address) } #endif - -#ifdef CONFIG_MODULES - -/* FIXME: Accessed without a lock --RR */ -extern struct list_head modules; - -static inline int kernel_text_address(unsigned long addr) -{ - int retval = 0; - struct module *mod; - - if (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext) - return 1; - - list_for_each_entry(mod, &modules, list) { - /* mod_bound tests for addr being inside the vmalloc'ed - * module area. Of course it'd be better to test only - * for the .text subset... */ - if (mod_bound((void *)addr, 0, mod)) { - retval = 1; - break; - } - } - - return retval; -} - -#else - -static inline int kernel_text_address(unsigned long addr) -{ - return (addr >= (unsigned long) &_stext && - addr <= (unsigned long) &_etext); -} - -#endif - static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) { int k; diff --git a/arch/x86_64/mm/hugetlbpage.c b/arch/x86_64/mm/hugetlbpage.c index bf5ea4753b28..d4515d57af34 100644 --- a/arch/x86_64/mm/hugetlbpage.c +++ b/arch/x86_64/mm/hugetlbpage.c @@ -232,8 +232,12 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) ret = -ENOMEM; goto out; } - add_to_page_cache(page, mapping, idx); + ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC); unlock_page(page); + if (ret) { + free_huge_page(page); + goto out; + } } set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); } diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8639f8bdaf15..bfa053f324f2 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -133,6 +133,7 @@ struct agp_bridge_data { u32 *gatt_table; u32 *gatt_table_real; unsigned long scratch_page; + unsigned long scratch_page_real; unsigned long gart_bus_addr; unsigned long gatt_bus_addr; u32 mode; @@ -145,7 +146,6 @@ struct agp_bridge_data { int needs_scratch_page; int aperture_size_idx; int num_aperture_sizes; - int num_of_masks; int capndx; int cant_use_aperture; diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index a88b5bc7df27..b4c93c4bc398 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -198,7 +198,6 @@ static struct aper_size_info_32 ali_generic_sizes[7] = static int __init ali_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = ali_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) ali_generic_sizes; agp_bridge.size_type = U32_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index ac867494a63c..93ebe05ce412 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -308,7 +308,8 @@ static int amd_insert_memory(agp_memory * mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -354,7 +355,6 @@ static struct gatt_mask amd_irongate_masks[] = static int __init amd_irongate_setup (struct pci_dev *pdev) { agp_bridge.masks = amd_irongate_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/amd-k8-agp.c b/drivers/char/agp/amd-k8-agp.c index aeb657b56c58..efa09382965f 100644 --- a/drivers/char/agp/amd-k8-agp.c +++ b/drivers/char/agp/amd-k8-agp.c @@ -81,7 +81,7 @@ static int x86_64_insert_memory(agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - addr = mem->memory[i]; + addr = agp_bridge.mask_memory(mem->memory[i], mem->type); tmp = addr; BUG_ON(tmp & 0xffffff0000000ffc); @@ -446,7 +446,6 @@ static void agp_x86_64_agp_enable(u32 mode) static int __init amd_8151_setup (struct pci_dev *pdev) { agp_bridge.masks = amd_8151_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_8151_sizes; agp_bridge.size_type = U32_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -512,6 +511,7 @@ static struct __initdata pci_driver agp_amdk8_pci_driver = { .probe = agp_amdk8_probe, }; +/* Not static due to IOMMU code calling it early. */ int __init agp_amdk8_init(void) { int ret_val; diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 65cf115d48ce..1dbb93606c9a 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -86,7 +86,7 @@ static int agp_find_max (void) { long memory, index, result; - memory = virt_to_phys(high_memory) >> 20; + memory = (num_physpages << PAGE_SHIFT) >> 20; index = 1; while ((memory > maxes_table[index].mem) && (index < 8)) @@ -123,8 +123,9 @@ static int agp_backend_initialize(struct pci_dev *dev) printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); return -ENOMEM; } - agp_bridge.scratch_page = virt_to_phys(addr); - agp_bridge.scratch_page = agp_bridge.mask_memory(agp_bridge.scratch_page, 0); + agp_bridge.scratch_page_real = virt_to_phys(addr); + agp_bridge.scratch_page = + agp_bridge.mask_memory(agp_bridge.scratch_page_real, 0); } size_value = agp_bridge.fetch_size(); @@ -165,8 +166,7 @@ static int agp_backend_initialize(struct pci_dev *dev) err_out: if (agp_bridge.needs_scratch_page == TRUE) { - agp_bridge.scratch_page &= ~(0x00000fff); - agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page)); + agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page_real)); } if (got_gatt) agp_bridge.free_gatt_table(); @@ -184,8 +184,7 @@ static void agp_backend_cleanup(void) vfree(agp_bridge.key_list); if (agp_bridge.needs_scratch_page == TRUE) { - agp_bridge.scratch_page &= ~(0x00000fff); - agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page)); + agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page_real)); } } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index c952ec4fc751..835f241a0443 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -110,7 +110,6 @@ void agp_free_memory(agp_memory * curr) } if (curr->page_count != 0) { for (i = 0; i < curr->page_count; i++) { - curr->memory[i] &= ~(0x00000fff); agp_bridge.agp_destroy_page(phys_to_virt(curr->memory[i])); } } @@ -158,7 +157,7 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type) agp_free_memory(new); return NULL; } - new->memory[i] = agp_bridge.mask_memory(virt_to_phys(addr), type); + new->memory[i] = virt_to_phys(addr); new->page_count++; } @@ -241,9 +240,6 @@ int agp_num_entries(void) int agp_copy_info(agp_kern_info * info) { - unsigned long page_mask = 0; - int i; - memset(info, 0, sizeof(agp_kern_info)); if (agp_bridge.type == NOT_SUPPORTED) { info->chipset = agp_bridge.type; @@ -259,11 +255,7 @@ int agp_copy_info(agp_kern_info * info) info->max_memory = agp_bridge.max_memory_agp; info->current_memory = atomic_read(&agp_bridge.current_memory_agp); info->cant_use_aperture = agp_bridge.cant_use_aperture; - - for(i = 0; i < agp_bridge.num_of_masks; i++) - page_mask |= agp_bridge.mask_memory(page_mask, i); - - info->page_mask = ~page_mask; + info->page_mask = ~0UL; return 0; } @@ -640,7 +632,8 @@ int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge.gatt_table[j] = mem->memory[i]; + agp_bridge.gatt_table[j] = + agp_bridge.mask_memory(mem->memory[i], mem->type); agp_bridge.tlb_flush(mem); return 0; diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 9d44cb858e99..4fb5cc400d0b 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -331,7 +331,6 @@ static unsigned long hp_zx1_mask_memory(unsigned long addr, int type) static int __init hp_zx1_setup (struct pci_dev *pdev __attribute__((unused))) { agp_bridge.masks = hp_zx1_masks; - agp_bridge.num_of_masks = 1; agp_bridge.dev_private_data = NULL; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.needs_scratch_page = FALSE; diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 9b9d676e971c..36256d815423 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -525,7 +525,6 @@ static unsigned long i460_mask_memory (unsigned long addr, int type) static int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused))) { - agp_bridge.num_of_masks = 1; agp_bridge.masks = i460_masks; agp_bridge.aperture_sizes = (void *) i460_sizes; agp_bridge.size_type = U8_APER_SIZE; diff --git a/drivers/char/agp/i7x05-agp.c b/drivers/char/agp/i7x05-agp.c index 0585d76548df..2b4b49af2b95 100644 --- a/drivers/char/agp/i7x05-agp.c +++ b/drivers/char/agp/i7x05-agp.c @@ -96,7 +96,6 @@ static void i7505_setup (u32 mode) static int __init intel_7505_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_7505_sizes; agp_bridge.size_type = U16_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index c9457777eb64..7fae8df7e722 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -153,7 +153,8 @@ insert: CACHE_FLUSH(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { OUTREG32(intel_i810_private.registers, - I810_PTE_BASE + (j * 4), mem->memory[i]); + I810_PTE_BASE + (j * 4), + agp_bridge.mask_memory(mem->memory[i], mem->type)); } CACHE_FLUSH(); @@ -219,11 +220,11 @@ static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) agp_free_memory(new); return NULL; } - new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type); + new->memory[0] = virt_to_phys(addr); new->page_count = 1; new->num_scratch_pages = 1; new->type = AGP_PHYS_MEMORY; - new->physical = virt_to_phys((void *) new->memory[0]); + new->physical = new->memory[0]; return new; } return NULL; @@ -251,7 +252,6 @@ static int __init intel_i810_setup(struct pci_dev *i810_dev) intel_i810_private.i810_dev = i810_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 2; agp_bridge.aperture_sizes = (void *) intel_i810_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -454,7 +454,8 @@ static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type) CACHE_FLUSH(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]); + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), + agp_bridge.mask_memory(mem->memory[i], mem->type)); CACHE_FLUSH(); @@ -514,11 +515,11 @@ static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) return(NULL); } - nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type); + nw->memory[0] = virt_to_phys(addr); nw->page_count = 1; nw->num_scratch_pages = 1; nw->type = AGP_PHYS_MEMORY; - nw->physical = virt_to_phys(addr); + nw->physical = nw->memory[0]; return(nw); } @@ -530,7 +531,6 @@ static int __init intel_i830_setup(struct pci_dev *i830_dev) intel_i830_private.i830_dev = i830_dev; agp_bridge.masks = intel_i810_masks; - agp_bridge.num_of_masks = 3; agp_bridge.aperture_sizes = (void *) intel_i830_sizes; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -974,7 +974,6 @@ static struct aper_size_info_8 intel_830mp_sizes[4] = static int __init intel_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_generic_sizes; agp_bridge.size_type = U16_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1004,7 +1003,6 @@ static int __init intel_generic_setup (struct pci_dev *pdev) static int __init intel_815_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_815_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 2; @@ -1035,7 +1033,6 @@ static int __init intel_815_setup (struct pci_dev *pdev) static int __init intel_820_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1065,7 +1062,6 @@ static int __init intel_820_setup (struct pci_dev *pdev) static int __init intel_830mp_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_830mp_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 4; @@ -1095,7 +1091,6 @@ static int __init intel_830mp_setup (struct pci_dev *pdev) static int __init intel_840_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1125,7 +1120,6 @@ static int __init intel_840_setup (struct pci_dev *pdev) static int __init intel_845_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1155,7 +1149,6 @@ static int __init intel_845_setup (struct pci_dev *pdev) static int __init intel_850_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -1185,7 +1178,6 @@ static int __init intel_850_setup (struct pci_dev *pdev) static int __init intel_860_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index a2d1ae7df5a9..d70f2d4de524 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -89,7 +89,6 @@ static struct gatt_mask sis_generic_masks[] = static int __init sis_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = sis_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) sis_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index d9d47c773c4e..8e8cb5290bd3 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -363,7 +363,8 @@ static int serverworks_insert_memory(agp_memory * mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + cur_gatt[GET_GATT_OFF(addr)] = + agp_bridge.mask_memory(mem->memory[i], mem->type); } agp_bridge.tlb_flush(mem); return 0; @@ -520,7 +521,6 @@ static int __init serverworks_setup (struct pci_dev *pdev) serverworks_private.svrwrks_dev = pdev; agp_bridge.masks = serverworks_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) serverworks_sizes; agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index b9ec5981f6ce..b3fc40fcbe3b 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -97,7 +97,6 @@ static struct gatt_mask via_generic_masks[] = static int __init via_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = via_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) via_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; @@ -203,9 +202,9 @@ static struct agp_device_ids via_agp_device_ids[] __initdata = .chipset_name = "Apollo ProSavage PM133" }, { - .device_id = PCI_DEVICE_ID_VIA_8235_0, - .chipset = VIA_P4X400, - .chipset_name = "P4X400" + .device_id = PCI_DEVICE_ID_VIA_8754, + .chipset = VIA_P4X, + .chipset_name = "Apollo P4X333/P4X400" }, { }, /* dummy final entry, always present */ }; diff --git a/drivers/char/agp/via-kt400.c b/drivers/char/agp/via-kt400.c index b23b19ab90c9..235459ce7d38 100644 --- a/drivers/char/agp/via-kt400.c +++ b/drivers/char/agp/via-kt400.c @@ -122,7 +122,6 @@ static int __init agp_via_probe (struct pci_dev *dev, const struct pci_device_id agp_bridge.type = VIA_APOLLO_KT400_3; agp_bridge.capndx = cap_ptr; agp_bridge.masks = via_generic_masks; - agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) via_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c index 5c07c1afe1d1..7ca10753a594 100644 --- a/drivers/char/drm/radeon_mem.c +++ b/drivers/char/drm/radeon_mem.c @@ -130,16 +130,6 @@ static void free_block( struct mem_block *p ) } } -static void print_heap( struct mem_block *heap ) -{ - struct mem_block *p; - - for (p = heap->next ; p != heap ; p = p->next) - DRM_DEBUG("0x%x..0x%x (0x%x) -- owner %d\n", - p->start, p->start + p->size, - p->size, p->pid); -} - /* Initialize. How to check for an uninitialized heap? */ static int init_heap(struct mem_block **heap, int start, int size) diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 6e7707bd4f9e..9bf169a196f1 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -1209,7 +1209,7 @@ static int fdc_request_regions(void) TRACE_FUN(ft_t_flow); if (ft_mach2 || ft_probe_fc10) { - if (check_region(fdc.sra, 8) < 0) { + if (!request_region(fdc.sra, 8, "fdc (ft)")) { #ifndef BROKEN_FLOPPY_DRIVER TRACE_EXIT -EBUSY; #else @@ -1217,10 +1217,8 @@ static int fdc_request_regions(void) "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); #endif } - request_region(fdc.sra, 8, "fdc (ft)"); } else { - if (check_region(fdc.sra, 6) < 0 || - check_region(fdc.dir, 1) < 0) { + if (!request_region(fdc.sra, 6, "fdc (ft)")) { #ifndef BROKEN_FLOPPY_DRIVER TRACE_EXIT -EBUSY; #else @@ -1228,8 +1226,15 @@ static int fdc_request_regions(void) "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); #endif } - request_region(fdc.sra, 6, "fdc (ft)"); - request_region(fdc.sra + 7, 1, "fdc (ft)"); + if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { +#ifndef BROKEN_FLOPPY_DRIVER + release_region(fdc.sra, 6); + TRACE_EXIT -EBUSY; +#else + TRACE(ft_t_warn, +"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); +#endif + } } TRACE_EXIT 0; } diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c index 67f8f6223422..72bb9b05f260 100644 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ b/drivers/char/ftape/zftape/zftape-ctl.c @@ -790,13 +790,6 @@ int _zft_close(void) zft_uninit_mem(); going_offline = 0; zft_offline = 1; - } else if (zft_dirty()) { - TRACE(ft_t_noise, "Keeping module locked in memory because:\n" - KERN_INFO "header segments need updating: %s\n" - KERN_INFO "tape not at BOT : %s", - (zft_volume_table_changed || zft_header_changed) - ? "yes" : "no", - zft_tape_at_lbot(&zft_pos) ? "no" : "yes"); } else if (zft_cmpr_lock(0 /* don't load */) == 0) { (*zft_cmpr_ops->reset)(); /* unlock it again */ } diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h index 91a2f2db7796..6c5a2532a3cc 100644 --- a/drivers/char/ftape/zftape/zftape-ctl.h +++ b/drivers/char/ftape/zftape/zftape-ctl.h @@ -47,7 +47,6 @@ extern int zft_resid; extern void zft_reset_position(zft_position *pos); extern int zft_check_write_access(zft_position *pos); extern int zft_def_idle_state(void); -extern int zft_dirty(void); /* hooks for the VFS interface */ diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 9af004b642b5..6c787bf5172e 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -404,11 +404,20 @@ static struct miscdevice rtc_gen_dev = int __init rtc_generic_init(void) { + int retval; - printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); + printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); - misc_register(&rtc_gen_dev); - create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL); + retval = misc_register(&rtc_gen_dev); + if(retval < 0) + return retval; + +#ifdef CONFIG_PROC_FS + if((create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL)) == NULL){ + misc_deregister(&rtc_gen_dev); + return -ENOMEM; + } +#endif return 0; } diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index 4f3e16c394b8..dc026ce7a9f3 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -688,9 +688,10 @@ static int __init nwflash_init(void) printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n", NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024)); - misc_register(&flash_miscdev); - - ret = 0; + ret = misc_register(&flash_miscdev); + if (ret < 0) { + iounmap((void *)FLASH_BASE); + } } out: return ret; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 6698a20041b0..29c856b8a5d3 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2499,6 +2499,11 @@ static int __init sx_init(void) sx_debug=-1; } + if (misc_register(&sx_fw_device) < 0) { + printk(KERN_ERR "SX: Unable to register firmware loader driver.\n"); + return -EIO; + } + #ifdef CONFIG_PCI if (pci_present ()) { #ifndef TWO_ZERO @@ -2643,11 +2648,8 @@ static int __init sx_init(void) } if (found) { printk (KERN_INFO "sx: total of %d boards detected.\n", found); - - if (misc_register(&sx_fw_device) < 0) { - printk(KERN_ERR "SX: Unable to register firmware loader driver.\n"); - return -EIO; - } + } else { + misc_deregister(&sx_fw_device); } func_exit(); diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index fc93acbc6dc1..7a1f939da5bb 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -474,6 +474,7 @@ int tosh_probe(void) int __init tosh_init(void) { + int retval; /* are we running on a Toshiba laptop */ if (tosh_probe()!=0) @@ -483,17 +484,21 @@ int __init tosh_init(void) TOSH_VERSION"\n"); /* set the port to use for Fn status if not specified as a parameter */ - if (tosh_fn==0x00) tosh_set_fn_port(); /* register the device file */ + retval = misc_register(&tosh_device); + if(retval < 0) + return retval; - misc_register(&tosh_device); - +#ifdef CONFIG_PROC_FS /* register the proc entry */ - - create_proc_info_entry("toshiba", 0, NULL, tosh_get_info); + if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){ + misc_deregister(&tosh_device); + return -ENOMEM; + } +#endif return 0; } diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index 849053231fb7..df7a7740b1d4 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -385,15 +385,14 @@ setup_asuscom(struct IsdnCard *card) bytecnt = 8; cs->hw.asus.cfg_reg = card->para[1]; cs->irq = card->para[0]; - if (check_region((cs->hw.asus.cfg_reg), bytecnt)) { + if (!request_region((cs->hw.asus.cfg_reg), bytecnt, + "asuscom isdn")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.asus.cfg_reg, cs->hw.asus.cfg_reg + bytecnt); return (0); - } else { - request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn"); } printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", cs->hw.asus.cfg_reg, cs->irq); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 12b11ba6b8fd..a796a9847651 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -746,16 +746,14 @@ setup_avm_pcipnp(struct IsdnCard *card) } ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; - if (check_region((cs->hw.avm.cfg_reg), 32)) { + if (!request_region((cs->hw.avm.cfg_reg), 32, (cs->subtyp == AVM_FRITZ_PCI) + ? "avm PCI" : "avm PnP")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 31); return (0); - } else { - request_region(cs->hw.avm.cfg_reg, 32, - (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP"); } switch (cs->subtyp) { case AVM_FRITZ_PCI: diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 5f714ed7633b..0068a5154c81 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -270,13 +270,11 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) int __init sct_alloc_io(u_int adr, u_int len) { - if (check_region(adr, len)) { + if (!request_region(adr, len, "scitel")) { printk(KERN_WARNING "HiSax: Scitel port %#x-%#x already in use\n", adr, adr + len); return (1); - } else { - request_region(adr, len, "scitel"); } return(0); } diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index 6f44fa490fce..d7d4e5ff88a2 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -357,15 +357,13 @@ setup_enternow_pci(struct IsdnCard *card) printk(KERN_INFO "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { + if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) { printk(KERN_WARNING "HiSax: %s config port %lx-%lx already in use\n", CardType[card->typ], cs->hw.njet.base, cs->hw.njet.base + bytecnt); return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN"); } reset_enpci(cs); cs->hw.njet.last_is0 = 0; diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c index 1f67738b849d..ba3fa3e4d5c4 100644 --- a/drivers/isdn/hisax/mic.c +++ b/drivers/isdn/hisax/mic.c @@ -214,15 +214,13 @@ setup_mic(struct IsdnCard *card) cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; - if (check_region((cs->hw.mic.cfg_reg), bytecnt)) { + if (!request_region((cs->hw.mic.cfg_reg), bytecnt, "mic isdn")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.mic.cfg_reg, cs->hw.mic.cfg_reg + bytecnt); return (0); - } else { - request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn"); } printk(KERN_INFO diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index 289b330ee697..e7bddb35b6e1 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -213,15 +213,13 @@ setup_netjet_u(struct IsdnCard *card) printk(KERN_INFO "NETspider-U: PCI card configured at %#lx IRQ %d\n", cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { + if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) { printk(KERN_WARNING "HiSax: %s config port %#lx-%#lx already in use\n", CardType[card->typ], cs->hw.njet.base, cs->hw.njet.base + bytecnt); return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn"); } reset_netjet_u(cs); cs->dc_hw_ops = &netjet_dc_ops; diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c index 6944acbaea53..5ad32e1c365f 100644 --- a/drivers/isdn/hisax/s0box.c +++ b/drivers/isdn/hisax/s0box.c @@ -250,15 +250,14 @@ setup_s0box(struct IsdnCard *card) cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; cs->irq = card->para[0]; - if (check_region(cs->hw.teles3.cfg_reg,8)) { + if (!request_region(cs->hw.teles3.cfg_reg,8, "S0Box parallel I/O")) { printk(KERN_WARNING "HiSax: %s ports %x-%x already in use\n", CardType[cs->typ], cs->hw.teles3.cfg_reg, cs->hw.teles3.cfg_reg + 7); return 0; - } else - request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O"); + } printk(KERN_INFO "HiSax: %s config irq:%d isac:0x%x cfg:0x%x\n", CardType[cs->typ], cs->irq, diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c index 1ce0d80ab433..29a97bab0a11 100644 --- a/drivers/isdn/hisax/saphir.c +++ b/drivers/isdn/hisax/saphir.c @@ -265,15 +265,14 @@ setup_saphir(struct IsdnCard *card) cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; cs->irq = card->para[0]; - if (check_region((cs->hw.saphir.cfg_reg), 6)) { + if (!request_region((cs->hw.saphir.cfg_reg), 6, "saphir")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.saphir.cfg_reg, cs->hw.saphir.cfg_reg + 5); return (0); - } else - request_region(cs->hw.saphir.cfg_reg,6, "saphir"); + } printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n", diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 6f681a6374d1..8b1575d0af38 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -689,15 +689,13 @@ ready: * here, it would fail. */ if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && - check_region((cs->hw.sedl.cfg_reg), bytecnt)) { + (!request_region((cs->hw.sedl.cfg_reg), bytecnt, "sedlbauer isdn"))) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.sedl.cfg_reg, cs->hw.sedl.cfg_reg + bytecnt); return (0); - } else { - request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn"); } printk(KERN_INFO diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index e05f07b43e9c..80107b58067a 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -196,13 +196,12 @@ get_io_range(struct IsdnCardState *cs) for (i=0;i<64;i++) { adr = cs->hw.spt.cfg_reg + i *1024; - if (check_region(adr, 8)) { + if (!request_region(adr, 8, "sportster")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[cs->typ], adr, adr + 8); break; - } else - request_region(adr, 8, "sportster"); + } } if (i==64) return(1); diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 7baa35361b2e..2df163c53331 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -249,15 +249,13 @@ setup_teles0(struct IsdnCard *card) } cs->irq = card->para[0]; if (cs->hw.teles0.cfg_reg) { - if (check_region(cs->hw.teles0.cfg_reg, 8)) { + if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", CardType[card->typ], cs->hw.teles0.cfg_reg, cs->hw.teles0.cfg_reg + 8); return (0); - } else { - request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg"); } } if (cs->hw.teles0.cfg_reg) { diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 904d1b08fffa..67805d213ba2 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -844,16 +844,14 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, pci_ioaddr, pci_irq); - if (check_region((cs->hw.w6692.iobase), 256)) { + if (!request_region((cs->hw.w6692.iobase), 256, + id_list[cs->subtyp].card_name)) { printk(KERN_WARNING "HiSax: %s I/O ports %x-%x already in use\n", id_list[cs->subtyp].card_name, cs->hw.w6692.iobase, cs->hw.w6692.iobase + 255); return (0); - } else { - request_region(cs->hw.w6692.iobase, 256, - id_list[cs->subtyp].card_name); } #else printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index 304b5f219bc5..c6073d342405 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -140,6 +140,7 @@ int __init anslcd_init(void) { int a; + int retval; struct device_node* node; node = find_devices("lcd"); @@ -150,7 +151,12 @@ anslcd_init(void) anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20); - misc_register(&anslcd_dev); + retval = misc_register(&anslcd_dev); + if(retval < 0){ + printk(KERN_INFO "LCD: misc_register failed\n"); + iounmap(anslcd_ptr); + return retval; + } #ifdef DEBUG printk(KERN_DEBUG "LCD: init\n"); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 7bc47778135d..9161022d90c9 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2702,8 +2702,10 @@ static struct miscdevice pmu_device = { void pmu_device_init(void) { - if (via) - misc_register(&pmu_device); + if (!via) + return; + if (misc_register(&pmu_device) < 0) + printk(KERN_ERR "via-pmu: cannot register misc device.\n"); } #endif /* CONFIG_PMAC_PBOOK */ diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 3bb653489391..ea592973e28f 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -1052,8 +1052,10 @@ static struct miscdevice pmu_device = { void pmu_device_init(void) { - if (via) - misc_register(&pmu_device); + if (!via) + return; + if (misc_register(&pmu_device) < 0) + printk(KERN_ERR "via-pmu68k: cannot register misc device.\n"); } #endif /* CONFIG_PMAC_PBOOK */ diff --git a/drivers/md/md.c b/drivers/md/md.c index a2c2d9649dfa..924f08aed568 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -578,10 +578,19 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->level = sb->level; mddev->layout = sb->layout; mddev->raid_disks = sb->raid_disks; - mddev->state = sb->state; mddev->size = sb->size; mddev->events = md_event(sb); - + + if (sb->state & (1<<MD_SB_CLEAN)) + mddev->recovery_cp = MaxSector; + else { + if (sb->events_hi == sb->cp_events_hi && + sb->events_lo == sb->cp_events_lo) { + mddev->recovery_cp = sb->recovery_cp; + } else + mddev->recovery_cp = 0; + } + memcpy(mddev->uuid+0, &sb->set_uuid0, 4); memcpy(mddev->uuid+4, &sb->set_uuid1, 4); memcpy(mddev->uuid+8, &sb->set_uuid2, 4); @@ -657,10 +666,22 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->md_minor = mddev->__minor; sb->not_persistent = !mddev->persistent; sb->utime = mddev->utime; - sb->state = mddev->state; + sb->state = 0; sb->events_hi = (mddev->events>>32); sb->events_lo = (u32)mddev->events; + if (mddev->in_sync) + { + sb->recovery_cp = mddev->recovery_cp; + sb->cp_events_hi = (mddev->events>>32); + sb->cp_events_lo = (u32)mddev->events; + if (mddev->recovery_cp == MaxSector) { + printk(KERN_INFO "md: marking sb clean...\n"); + sb->state = (1<< MD_SB_CLEAN); + } + } else + sb->recovery_cp = 0; + sb->layout = mddev->layout; sb->chunk_size = mddev->chunk_size; @@ -1198,7 +1219,7 @@ static int analyze_sbs(mddev_t * mddev) goto abort; } - if ((mddev->state != (1 << MD_SB_CLEAN)) && ((mddev->level == 1) || + if ((mddev->recovery_cp != MaxSector) && ((mddev->level == 1) || (mddev->level == 4) || (mddev->level == 5))) printk(NOT_CLEAN_IGNORE, mdidx(mddev)); @@ -1469,13 +1490,11 @@ static int do_md_run(mddev_t * mddev) mddev->pers = NULL; return -EINVAL; } - - mddev->in_sync = (mddev->state & (1<<MD_SB_CLEAN)); - /* if personality doesn't have "sync_request", then - * a dirty array doesn't mean anything - */ if (mddev->pers->sync_request) - mddev->state &= ~(1 << MD_SB_CLEAN); + mddev->in_sync = 0; + else + mddev->in_sync = 1; + md_update_sb(mddev); md_recover_arrays(); set_capacity(disk, md_size[mdidx(mddev)]<<1); @@ -1502,6 +1521,8 @@ static int restart_array(mddev_t *mddev) if (!mddev->ro) goto out; + mddev->in_sync = 0; + md_update_sb(mddev); mddev->ro = 0; set_disk_ro(disk, 0); @@ -1541,7 +1562,7 @@ static int do_md_stop(mddev_t * mddev, int ro) if (mddev->pers) { if (mddev->sync_thread) { if (mddev->recovery_running > 0) - mddev->recovery_running = -EINTR; + mddev->recovery_running = -1; md_unregister_thread(mddev->sync_thread); mddev->sync_thread = NULL; } @@ -1567,14 +1588,8 @@ static int do_md_stop(mddev_t * mddev, int ro) mddev->ro = 0; } if (mddev->raid_disks) { - /* - * mark it clean only if there was no resync - * interrupted. - */ - if (mddev->in_sync) { - printk(KERN_INFO "md: marking sb clean...\n"); - mddev->state |= 1 << MD_SB_CLEAN; - } + /* mark array as shutdown cleanly */ + mddev->in_sync = 1; md_update_sb(mddev); } if (ro) @@ -1840,7 +1855,9 @@ static int get_array_info(mddev_t * mddev, void * arg) info.not_persistent= !mddev->persistent; info.utime = mddev->utime; - info.state = mddev->state; + info.state = 0; + if (mddev->recovery_cp == MaxSector) + info.state = (1<<MD_SB_CLEAN); info.active_disks = active; info.working_disks = working; info.failed_disks = failed; @@ -2111,7 +2128,10 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) /* don't set __minor, it is determined by which /dev/md* was * openned */ - mddev->state = info->state; + if (info->state & (1<<MD_SB_CLEAN)) + mddev->recovery_cp = MaxSector; + else + mddev->recovery_cp = 0; mddev->persistent = ! info->not_persistent; mddev->layout = info->layout; @@ -2742,7 +2762,7 @@ int unregister_md_personality(int pnum) void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors) { - rdev->bdev->bd_disk->sync_io += nr_sectors; + rdev->bdev->bd_contains->bd_disk->sync_io += nr_sectors; } static int is_mddev_idle(mddev_t *mddev) @@ -2754,7 +2774,7 @@ static int is_mddev_idle(mddev_t *mddev) idle = 1; ITERATE_RDEV(mddev,rdev,tmp) { - struct gendisk *disk = rdev->bdev->bd_disk; + struct gendisk *disk = rdev->bdev->bd_contains->bd_disk; curr_events = disk->read_sectors + disk->write_sectors - disk->sync_io; if ((curr_events - rdev->last_events) > 32) { rdev->last_events = curr_events; @@ -2770,7 +2790,8 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) atomic_sub(blocks, &mddev->recovery_active); wake_up(&mddev->recovery_wait); if (!ok) { - mddev->recovery_running = -EIO; + mddev->recovery_error = -EIO; + mddev->recovery_running = -1; md_recover_arrays(); // stop recovery, signal do_sync .... } @@ -2815,8 +2836,10 @@ static void md_do_sync(void *data) printk(KERN_INFO "md: delaying resync of md%d until md%d " "has finished resync (they share one or more physical units)\n", mdidx(mddev), mdidx(mddev2)); - if (mddev < mddev2) /* arbitrarily yield */ + if (mddev < mddev2) {/* arbitrarily yield */ mddev->curr_resync = 1; + yield(); + } if (wait_event_interruptible(resync_wait, mddev2->curr_resync < 2)) { flush_curr_signals(); @@ -2839,7 +2862,7 @@ static void md_do_sync(void *data) is_mddev_idle(mddev); /* this also initializes IO event counters */ for (m = 0; m < SYNC_MARKS; m++) { mark[m] = jiffies; - mark_cnt[m] = 0; + mark_cnt[m] = mddev->recovery_cp; } last_mark = 0; mddev->resync_mark = mark[last_mark]; @@ -2855,7 +2878,13 @@ static void md_do_sync(void *data) atomic_set(&mddev->recovery_active, 0); init_waitqueue_head(&mddev->recovery_wait); last_check = 0; - for (j = 0; j < max_sectors;) { + + mddev->recovery_error = 0; + + if (mddev->recovery_cp) + printk(KERN_INFO "md: resuming recovery of md%d from checkpoint.\n", mdidx(mddev)); + + for (j = mddev->recovery_cp; j < max_sectors;) { int sectors; sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min); @@ -2925,16 +2954,25 @@ static void md_do_sync(void *data) */ out: wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); + + if (mddev->recovery_running < 0 && + !mddev->recovery_error && mddev->curr_resync > 2) + { + /* interrupted but no write errors */ + printk(KERN_INFO "md: checkpointing recovery of md%d.\n", mdidx(mddev)); + mddev->recovery_cp = mddev->curr_resync; + } + /* tell personality that we are finished */ mddev->pers->sync_request(mddev, max_sectors, 1); skip: mddev->curr_resync = 0; if (err) - mddev->recovery_running = err; + mddev->recovery_running = -1; if (mddev->recovery_running > 0) mddev->recovery_running = 0; if (mddev->recovery_running == 0) - mddev->in_sync = 1; + mddev->recovery_cp = MaxSector; md_recover_arrays(); } @@ -3015,14 +3053,16 @@ void md_do_recovery(void *data) ITERATE_RDEV(mddev,rdev,rtmp) if (rdev->raid_disk < 0 && !rdev->faulty) { - if (mddev->pers->hot_add_disk(mddev,rdev)) + if (mddev->pers->hot_add_disk(mddev,rdev)) { mddev->spares++; + mddev->recovery_cp = 0; + } else break; } } - if (!mddev->spares && mddev->in_sync) { + if (!mddev->spares && (mddev->recovery_cp == MaxSector )) { /* nothing we can do ... */ goto unlock; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 55e9a01d4e29..9b3fcf9368c1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -975,7 +975,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) sector_t max_sector, nr_sectors; int disk, partial; - if (sector_nr == 0) + if (!conf->r1buf_pool) if (init_resync(conf)) return -ENOMEM; @@ -1149,7 +1149,7 @@ static int run(mddev_t *mddev) conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; if (conf->working_disks == 1) - mddev->state |= (1 << MD_SB_CLEAN); + mddev->recovery_cp = MaxSector; conf->resync_lock = SPIN_LOCK_UNLOCKED; init_waitqueue_head(&conf->wait_idle); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3ef80e69f864..090058085cc5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1471,7 +1471,7 @@ static int run (mddev_t *mddev) } if (mddev->degraded == 1 && - !(mddev->state & (1<<MD_SB_CLEAN))) { + mddev->recovery_cp != MaxSector) { printk(KERN_ERR "raid5: cannot start dirty degraded array for md%d\n", mdidx(mddev)); goto abort; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index b93d978586be..3dbad22e6513 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -460,6 +460,7 @@ enum vortex_chips { CH_3CCFEM656_1, CH_3C450, + CH_3C920, }; @@ -551,6 +552,8 @@ static struct vortex_chip_info { MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, + {"3c920 Tornado", + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {0,}, /* 0 terminated list. */ }; @@ -594,6 +597,7 @@ static struct pci_device_id vortex_pci_tbl[] __devinitdata = { { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, + { 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 }, {0,} /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); diff --git a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c index e5c8d53833ad..42bc6c9d0046 100644 --- a/drivers/net/aironet4500_proc.c +++ b/drivers/net/aironet4500_proc.c @@ -42,6 +42,8 @@ #define DEV_AWC_INFO 1 #define DEV_AWC 1 +spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; + struct awc_proc_private{ struct ctl_table_header * sysctl_header; struct ctl_table * proc_table; @@ -293,10 +295,9 @@ int awc_proc_fun(ctl_table *ctl, int write, struct file * filp, }; if (!write && rid->selector->may_change) { - save_flags(flags); - cli(); + spin_lock_irqsave(&driver_lock, flags); awc_readrid(dev,rid,rid_dir->buff + rid->offset); - restore_flags(flags); + spin_unlock_irqrestore(&driver_lock, flags); }; if (rid->array > 1 || rid->bits > 32){ @@ -325,9 +326,8 @@ int awc_proc_fun(ctl_table *ctl, int write, struct file * filp, } } if (write) { - save_flags(flags); - cli(); - + spin_lock_irqsave(&driver_lock, flags); + if (rid->selector->MAC_Disable_at_write){ awc_disable_MAC(dev); }; @@ -335,8 +335,7 @@ int awc_proc_fun(ctl_table *ctl, int write, struct file * filp, if (rid->selector->MAC_Disable_at_write){ awc_enable_MAC(dev); }; - restore_flags(flags); - + spin_lock_irqsave(&driver_lock, flags); }; DEBUG(0x20000,"awc proc ret %x \n",retv); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 5753cbd3c991..efa1d9db6d85 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -189,8 +189,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) break; case 4000000: - save_flags(flags); - cli(); + local_irq_save(flags); si->hscr0 = 0; @@ -210,7 +209,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) sa1100_irda_rx_alloc(si); sa1100_irda_rx_dma_start(si); - restore_flags(flags); + local_irq_restore(flags); break; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 794e8e5f131e..4ee9d0d8d767 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1847,15 +1847,15 @@ static int netdev_close(struct net_device *dev) #ifdef __i386__ if (debug > 2) { - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - np->tx_ring_dma); + printk("\n"KERN_DEBUG" Tx ring at %9.9Lx:\n", + (u64) np->tx_ring_dma); for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++) printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", i, le32_to_cpu(np->tx_ring[i].status), le32_to_cpu(np->tx_ring[i].first_addr), le32_to_cpu(np->tx_done_q[i].status)); - printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", - np->rx_ring_dma, np->rx_done_q); + printk(KERN_DEBUG " Rx ring at %9.9Lx -> %p:\n", + (u64) np->rx_ring_dma, np->rx_done_q); if (np->rx_done_q) for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2c14942cbb00..687a9781ee71 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -558,9 +558,15 @@ struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, b = pci_alloc_bus(); if (!b) return NULL; + + b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL); + if (!b->dev){ + kfree(b); + return NULL; + } + list_add_tail(&b->node, &pci_root_buses); - b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL); memset(b->dev,0,sizeof(*(b->dev))); sprintf(b->dev->bus_id,"pci%d",bus); strcpy(b->dev->name,"Host/PCI Bridge"); diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index f3cd6bb7b18d..0361f8c1f9ef 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -886,7 +886,7 @@ static void probeLptPort(unsigned idx) instances[idx].run_flag = 0; init_timer(&instances[idx].timer_list); instances[idx].timer_list.function = bpp_wake_up; - if (check_region(lpAddr,3)) return; + if (!request_region(lpAddr,3, dev_name)) return; /* * First, make sure the instance exists. Do this by writing to @@ -904,7 +904,6 @@ static void probeLptPort(unsigned idx) unsigned save; instances[idx].present = 1; - request_region(lpAddr,3, dev_name); save = inb_p(lpAddr+2); for (testvalue=0; testvalue<BPP_DELAY; testvalue++) ; @@ -921,7 +920,9 @@ static void probeLptPort(unsigned idx) instances[idx].enhanced = 1; outb_p(save, lpAddr+2); } - + else { + release_region(lpAddr,3); + } /* * Leave the port in compat idle mode. */ diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 586b3d61430d..f953eaf73d32 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -892,6 +892,10 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } pchild->tables = kmalloc(tbls_size, GFP_KERNEL); + if (pchild->tables == NULL){ + printk("envctrl: Failed to allocate table.\n"); + return; + } len = prom_getproperty(node, "tables", (char *) pchild->tables, tbls_size); if (len <= 0) { diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 0eaded61130b..11112c7be145 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -36,7 +36,6 @@ #include <linux/fcntl.h> #include <linux/ptrace.h> #include <linux/mm.h> -#include <linux/malloc.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/irq.h> diff --git a/drivers/sgi/char/streamable.c b/drivers/sgi/char/streamable.c index 6831e267dc3a..71d47b184d74 100644 --- a/drivers/sgi/char/streamable.c +++ b/drivers/sgi/char/streamable.c @@ -309,10 +309,27 @@ static struct miscdevice dev_input_mouse = { void streamable_init (void) { - printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n", + if (misc_register (&dev_gfx) < 0) { + printk(KERN_ERR + "streamable: cannot register gfx misc device.\n"); + return; + } + + if (misc_register (&dev_input_keyboard) < 0) { + printk(KERN_ERR + "streamable: cannot register keyboard misc device.\n"); + misc_deregister(&dev_gfx); + return; + } + + if (misc_register (&dev_input_mouse) < 0) { + printk(KERN_ERR + "streamable: cannot register mouse misc device.\n"); + misc_deregister(&dev_input_keyboard); + misc_deregister(&dev_gfx); + return; + } + + printk ("streamable: misc devices registered (keyb:%d, gfx:%d)\n", SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR); - - misc_register (&dev_gfx); - misc_register (&dev_input_keyboard); - misc_register (&dev_input_mouse); } diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c index 76a425812a87..253e1cd537b0 100644 --- a/drivers/sgi/char/usema.c +++ b/drivers/sgi/char/usema.c @@ -176,9 +176,12 @@ static struct miscdevice dev_usemaclone = { void usema_init(void) { + if (misc_register(&dev_usemaclone) < 0) { + printk(KERN_ERR "usemaclone: cannot register misc device.\n"); + return; + } printk("usemaclone misc device registered (minor: %d)\n", - SGI_USEMACLONE); - misc_register(&dev_usemaclone); + SGI_USEMACLONE); } EXPORT_SYMBOL(usema_init); diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 1b56a5ddbfb9..e206645d0929 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -6906,21 +6906,19 @@ static int ixj_selfprobe(IXJ *j) /* Internet PhoneJack Lite */ { j->cardtype = QTI_PHONEJACK_LITE; - if (check_region(j->XILINXbase, 4)) { + if (!request_region(j->XILINXbase, 4, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 4, "ixj control"); j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); } else { j->cardtype = QTI_LINEJACK; - if (check_region(j->XILINXbase, 8)) { + if (!request_region(j->XILINXbase, 8, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 8, "ixj control"); } } else if (j->dsp.low == 0x22) { j->cardtype = QTI_PHONEJACK_PCI; @@ -6941,19 +6939,17 @@ static int ixj_selfprobe(IXJ *j) } break; case QTI_LINEJACK: - if (check_region(j->XILINXbase, 8)) { + if (!request_region(j->XILINXbase, 8, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 8, "ixj control"); break; case QTI_PHONEJACK_LITE: case QTI_PHONEJACK_PCI: - if (check_region(j->XILINXbase, 4)) { + if (!request_region(j->XILINXbase, 4, "ixj control")) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase); return -1; } - request_region(j->XILINXbase, 4, "ixj control"); j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); break; diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 3246f790fed1..d98850e91055 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -181,6 +181,6 @@ config USB_XPAD This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called wacom.o. If you want to compile it as a + The module will be called xpad.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 6af6905572c9..5b4e92e6a616 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -386,6 +386,7 @@ static void __init fb_set_logocmap(struct fb_info *info) palette_cmap.red = palette_red; palette_cmap.green = palette_green; palette_cmap.blue = palette_blue; + palette_cmap.transp = NULL; for (i = 0; i < LINUX_LOGO_COLORS; i += n) { n = LINUX_LOGO_COLORS - i; @@ -767,6 +768,7 @@ fb_set_var(struct fb_var_screeninfo *var, struct fb_info *info) int fb_blank(int blank, struct fb_info *info) { + /* ??? Varible sized stack allocation. */ u16 black[info->cmap.len]; struct fb_cmap cmap; @@ -775,8 +777,7 @@ fb_blank(int blank, struct fb_info *info) if (blank) { memset(black, 0, info->cmap.len * sizeof(u16)); cmap.red = cmap.green = cmap.blue = black; - if (info->cmap.transp) - cmap.transp = black; + cmap.transp = info->cmap.transp ? black : NULL; cmap.start = info->cmap.start; cmap.len = info->cmap.len; } else diff --git a/fs/exec.c b/fs/exec.c index 8f0b41fd3a28..7f6f6a06fa0a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -45,6 +45,7 @@ #include <linux/ptrace.h> #include <linux/mount.h> #include <linux/security.h> +#include <linux/rmap-locking.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> @@ -292,12 +293,13 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a pgd_t * pgd; pmd_t * pmd; pte_t * pte; + struct pte_chain *pte_chain; if (page_count(page) != 1) printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address); pgd = pgd_offset(tsk->mm, address); - + pte_chain = pte_chain_alloc(GFP_KERNEL); spin_lock(&tsk->mm->page_table_lock); pmd = pmd_alloc(tsk->mm, pgd, address); if (!pmd) @@ -313,17 +315,19 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a flush_dcache_page(page); flush_page_to_ram(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); - page_add_rmap(page, pte); + pte_chain = page_add_rmap(page, pte, pte_chain); pte_unmap(pte); tsk->mm->rss++; spin_unlock(&tsk->mm->page_table_lock); /* no need for flush_tlb */ + pte_chain_free(pte_chain); return; out: spin_unlock(&tsk->mm->page_table_lock); __free_page(page); force_sig(SIGKILL, tsk); + pte_chain_free(pte_chain); return; } diff --git a/fs/mpage.c b/fs/mpage.c index c2e3a2d4e8c4..a44993cd7927 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -275,7 +275,8 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, prefetchw(&page->flags); list_del(&page->list); - if (!add_to_page_cache(page, mapping, page->index)) { + if (!add_to_page_cache(page, mapping, + page->index, GFP_KERNEL)) { bio = do_mpage_readpage(bio, page, nr_pages - page_idx, &last_block_in_bio, get_block); diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index c5e66aab4e97..93ba7610dde0 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -587,7 +587,9 @@ static int __ncptcp_rcv_proc(struct ncp_server *server) { } #endif type = ntohs(server->rcv.buf.type); +#ifdef CONFIG_NCPFS_PACKET_SIGNING cont:; +#endif if (type != NCP_REPLY) { if (datalen - 8 <= sizeof(server->unexpected_packet.data)) { *(__u16*)(server->unexpected_packet.data) = htons(type); diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 195e1a6dc037..f5065ab668cb 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -54,16 +54,13 @@ static struct file *do_open(char *name, int flags) static struct { char *name; int wsize; int rsize; } map[] = { - [NFSCTL_SVC]={"svc", sizeof(struct nfsctl_svc)}, - [NFSCTL_ADDCLIENT]={"add", sizeof(struct nfsctl_client)}, - [NFSCTL_DELCLIENT]={"del", sizeof(struct nfsctl_client)}, - [NFSCTL_EXPORT]={"export", sizeof(struct nfsctl_export)}, - [NFSCTL_UNEXPORT]={"unexport", sizeof(struct nfsctl_export)}, -#ifdef notyet - [NFSCTL_UGIDUPDATE]={"ugid", sizeof(struct nfsctl_uidmap)}, -#endif - [NFSCTL_GETFD]={"getfd", sizeof(struct nfsctl_fdparm), NFS_FHSIZE}, - [NFSCTL_GETFS]={"getfs", sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)}, + [NFSCTL_SVC]={".svc", sizeof(struct nfsctl_svc)}, + [NFSCTL_ADDCLIENT]={".add", sizeof(struct nfsctl_client)}, + [NFSCTL_DELCLIENT]={".del", sizeof(struct nfsctl_client)}, + [NFSCTL_EXPORT]={".export", sizeof(struct nfsctl_export)}, + [NFSCTL_UNEXPORT]={".unexport", sizeof(struct nfsctl_export)}, + [NFSCTL_GETFD]={".getfd", sizeof(struct nfsctl_fdparm), NFS_FHSIZE}, + [NFSCTL_GETFS]={".getfs", sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)}, }; long diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index b4b672ada9a5..fe8269fbc3bd 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -24,6 +24,7 @@ #include <linux/dcache.h> #include <linux/namei.h> #include <linux/mount.h> +#include <linux/hash.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> @@ -59,12 +60,9 @@ static inline int svc_expkey_hash(struct svc_expkey *item) int hash = item->ek_fsidtype; char * cp = (char*)item->ek_fsid; int len = (item->ek_fsidtype==0)?8:4; - while (len--) - hash += *cp++; - cp = (char*)&item->ek_client; - len = sizeof(item->ek_client); - while (len--) - hash += *cp++; + + hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); + hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); return hash & EXPKEY_HASHMASK; } @@ -239,17 +237,12 @@ static struct cache_head *export_table[EXPORT_HASHMAX]; static inline int svc_export_hash(struct svc_export *item) { - void *k[2]; - unsigned char *cp; - int rv, i; - k[0] = item->ex_client; - k[1] = item->ex_dentry; - - cp = (char*)k; - rv = 0; - for (i=0; i<sizeof(k); i++) - rv ^= cp[i]; - return rv & EXPORT_HASHMASK; + int rv; + + rv = hash_ptr(item->ex_client, EXPORT_HASHBITS); + rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS); + rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS); + return rv; } void svc_export_put(struct cache_head *item, struct cache_detail *cd) diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 3cb91cc3cb03..7a6ef7e5a31a 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -58,7 +58,7 @@ decode_time3(u32 *p, struct timespec *time) static inline u32 * decode_fh(u32 *p, struct svc_fh *fhp) { - int size; + unsigned int size; fh_init(fhp, NFS3_FHSIZE); size = ntohl(*p++); if (size > NFS3_FHSIZE) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 99d89405387d..24a0a912e7c0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -568,6 +568,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, resp->xbuf = &rqstp->rq_res; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; + resp->tagp = resp->p + 1; /* skip over status */ + /* reserve space for: status, taglen, tag, and opcnt */ resp->p += 3 + XDR_QUADLEN(args->taglen); resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; resp->taglen = args->taglen; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 906b727f8873..fba884d7d8d6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1728,8 +1728,17 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read WRITE32(maxcount); ADJUST_ARGS(); resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; - resp->p = resp->xbuf->tail[0].iov_base; + resp->xbuf->page_len = maxcount; + + /* set up page for remaining responses */ + svc_take_page(resp->rqstp); + resp->xbuf->tail[0].iov_base = + page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + resp->xbuf->tail[0].iov_len = 0; + resp->p = resp->xbuf->tail[0].iov_base; + resp->end = resp->p + PAGE_SIZE/4; + if (maxcount&3) { *(resp->p)++ = 0; resp->xbuf->tail[0].iov_base += maxcount&3; @@ -1753,11 +1762,6 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r svc_take_page(resp->rqstp); page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); - svc_take_page(resp->rqstp); - resp->xbuf->tail[0].iov_base = - page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); - resp->xbuf->tail[0].iov_len = 0; - maxcount = PAGE_SIZE; RESERVE_SPACE(4); @@ -1774,7 +1778,14 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r WRITE32(maxcount); ADJUST_ARGS(); resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; + + svc_take_page(resp->rqstp); + resp->xbuf->tail[0].iov_base = + page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + resp->xbuf->tail[0].iov_len = 0; resp->p = resp->xbuf->tail[0].iov_base; + resp->end = resp->p + PAGE_SIZE/4; + resp->xbuf->page_len = maxcount; if (maxcount&3) { *(resp->p)++ = 0; @@ -1803,6 +1814,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re WRITE32(0); WRITE32(0); ADJUST_ARGS(); + resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; maxcount = PAGE_SIZE; if (maxcount > readdir->rd_maxcount) @@ -1832,16 +1844,26 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re readdir->common.err == nfserr_readdir_nospc && readdir->buffer == page) nfserr = nfserr_readdir_nospc; - if (!nfserr) { - if (readdir->offset) - xdr_encode_hyper(readdir->offset, offset); + if (nfserr) + return nfserr; - p = readdir->buffer; - *p++ = 0; /* no more entries */ - *p++ = htonl(readdir->common.err == nfserr_eof); - resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); - } - return nfserr; + if (readdir->offset) + xdr_encode_hyper(readdir->offset, offset); + + p = readdir->buffer; + *p++ = 0; /* no more entries */ + *p++ = htonl(readdir->common.err == nfserr_eof); + resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + + /* allocate a page for the tail */ + svc_take_page(resp->rqstp); + resp->xbuf->tail[0].iov_base = + page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); + resp->xbuf->tail[0].iov_len = 0; + resp->p = resp->xbuf->tail[0].iov_base; + resp->end = resp->p + PAGE_SIZE/4; + + return 0; } static void @@ -2066,6 +2088,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compound * All that remains is to write the tag and operation count... */ struct iovec *iov; + p = resp->tagp; *p++ = htonl(resp->taglen); memcpy(p, resp->tag, resp->taglen); p += XDR_QUADLEN(resp->taglen); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 4d208cbaa5d9..7cc70b08b27d 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -46,20 +46,25 @@ enum { NFSD_Getfd, NFSD_Getfs, NFSD_List, + NFSD_Fh, + NFSD_Threads, + NFSD_END }; /* * write() for these nodes. */ -static ssize_t write_svc(struct file *file, const char *buf, size_t size); -static ssize_t write_add(struct file *file, const char *buf, size_t size); -static ssize_t write_del(struct file *file, const char *buf, size_t size); -static ssize_t write_export(struct file *file, const char *buf, size_t size); -static ssize_t write_unexport(struct file *file, const char *buf, size_t size); -static ssize_t write_getfd(struct file *file, const char *buf, size_t size); -static ssize_t write_getfs(struct file *file, const char *buf, size_t size); - -static ssize_t (*write_op[])(struct file *, const char *, size_t) = { +static ssize_t write_svc(struct file *file, char *buf, size_t size); +static ssize_t write_add(struct file *file, char *buf, size_t size); +static ssize_t write_del(struct file *file, char *buf, size_t size); +static ssize_t write_export(struct file *file, char *buf, size_t size); +static ssize_t write_unexport(struct file *file, char *buf, size_t size); +static ssize_t write_getfd(struct file *file, char *buf, size_t size); +static ssize_t write_getfs(struct file *file, char *buf, size_t size); +static ssize_t write_filehandle(struct file *file, char *buf, size_t size); +static ssize_t write_threads(struct file *file, char *buf, size_t size); + +static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Svc] = write_svc, [NFSD_Add] = write_add, [NFSD_Del] = write_del, @@ -67,32 +72,81 @@ static ssize_t (*write_op[])(struct file *, const char *, size_t) = { [NFSD_Unexport] = write_unexport, [NFSD_Getfd] = write_getfd, [NFSD_Getfs] = write_getfs, + [NFSD_Fh] = write_filehandle, + [NFSD_Threads] = write_threads, }; -static ssize_t fs_write(struct file *file, const char *buf, size_t size, loff_t *pos) +/* an argresp is stored in an allocated page and holds the + * size of the argument or response, along with it's content + */ +struct argresp { + ssize_t size; + char data[0]; +}; + +/* + * transaction based IO methods. + * The file expects a single write which triggers the transaction, and then + * possibly a read which collects the result - which is stored in a + * file-local buffer. + */ +static ssize_t TA_write(struct file *file, const char *buf, size_t size, loff_t *pos) { ino_t ino = file->f_dentry->d_inode->i_ino; + struct argresp *ar; + ssize_t rv = 0; + if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino]) return -EINVAL; - return write_op[ino](file, buf, size); + if (file->private_data) + return -EINVAL; /* only one write allowed per open */ + if (size > PAGE_SIZE - sizeof(struct argresp)) + return -EFBIG; + + ar = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!ar) + return -ENOMEM; + ar->size = 0; + down(&file->f_dentry->d_inode->i_sem); + if (file->private_data) + rv = -EINVAL; + else + file->private_data = ar; + up(&file->f_dentry->d_inode->i_sem); + if (rv) { + kfree(ar); + return rv; + } + if (copy_from_user(ar->data, buf, size)) + return -EFAULT; + + rv = write_op[ino](file, ar->data, size); + if (rv>0) { + ar->size = rv; + rv = size; + } + return rv; } -/* - * read(), open() and release() for getfs and getfd (read/write ones). - * IO on these is a simple transaction - you open() the file, write() to it - * and that generates a (stored) response. After that read() will simply - * access that response. - */ static ssize_t TA_read(struct file *file, char *buf, size_t size, loff_t *pos) { - if (!file->private_data) + struct argresp *ar; + ssize_t rv = 0; + + if (file->private_data == NULL) + rv = TA_write(file, buf, 0, pos); + if (rv < 0) + return rv; + + ar = file->private_data; + if (!ar) return 0; - if (*pos >= file->f_dentry->d_inode->i_size) + if (*pos >= ar->size) return 0; - if (*pos + size > file->f_dentry->d_inode->i_size) - size = file->f_dentry->d_inode->i_size - *pos; - if (copy_to_user(buf, file->private_data + *pos, size)) + if (*pos + size > ar->size) + size = ar->size - *pos; + if (copy_to_user(buf, ar->data + *pos, size)) return -EFAULT; *pos += size; return size; @@ -112,12 +166,8 @@ static int TA_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations writer_ops = { - .write = fs_write, -}; - -static struct file_operations reader_ops = { - .write = fs_write, +static struct file_operations transaction_ops = { + .write = TA_write, .read = TA_read, .open = TA_open, .release = TA_release, @@ -158,169 +208,224 @@ static struct file_operations exports_operations = { * Description of fs contents. */ static struct { char *name; struct file_operations *ops; int mode; } files[] = { - [NFSD_Svc] = {"svc", &writer_ops, S_IWUSR}, - [NFSD_Add] = {"add", &writer_ops, S_IWUSR}, - [NFSD_Del] = {"del", &writer_ops, S_IWUSR}, - [NFSD_Export] = {"export", &writer_ops, S_IWUSR}, - [NFSD_Unexport] = {"unexport", &writer_ops, S_IWUSR}, - [NFSD_Getfd] = {"getfd", &reader_ops, S_IWUSR|S_IRUSR}, - [NFSD_Getfs] = {"getfs", &reader_ops, S_IWUSR|S_IRUSR}, + [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR}, + [NFSD_Add] = {".add", &transaction_ops, S_IWUSR}, + [NFSD_Del] = {".del", &transaction_ops, S_IWUSR}, + [NFSD_Export] = {".export", &transaction_ops, S_IWUSR}, + [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR}, + [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, + [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, }; /*----------------------------------------------------------------------------*/ /* * payload - write methods + * If the method has a response, the response should be put in buf, + * and the length returned. Otherwise return 0 or and -error. */ -static ssize_t write_svc(struct file *file, const char *buf, size_t size) +static ssize_t write_svc(struct file *file, char *buf, size_t size) { - struct nfsctl_svc data; - if (size < sizeof(data)) + struct nfsctl_svc *data; + if (size < sizeof(*data)) return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - return nfsd_svc(data.svc_port, data.svc_nthreads); + data = (struct nfsctl_svc*) buf; + return nfsd_svc(data->svc_port, data->svc_nthreads); } -static ssize_t write_add(struct file *file, const char *buf, size_t size) +static ssize_t write_add(struct file *file, char *buf, size_t size) { - struct nfsctl_client data; - if (size < sizeof(data)) + struct nfsctl_client *data; + if (size < sizeof(*data)) return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - return exp_addclient(&data); + data = (struct nfsctl_client *)buf; + return exp_addclient(data); } -static ssize_t write_del(struct file *file, const char *buf, size_t size) +static ssize_t write_del(struct file *file, char *buf, size_t size) { - struct nfsctl_client data; - if (size < sizeof(data)) + struct nfsctl_client *data; + if (size < sizeof(*data)) return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - return exp_delclient(&data); + data = (struct nfsctl_client *)buf; + return exp_delclient(data); } -static ssize_t write_export(struct file *file, const char *buf, size_t size) +static ssize_t write_export(struct file *file, char *buf, size_t size) { - struct nfsctl_export data; - if (size < sizeof(data)) + struct nfsctl_export *data; + if (size < sizeof(*data)) return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - return exp_export(&data); + data = (struct nfsctl_export*)buf; + return exp_export(data); } -static ssize_t write_unexport(struct file *file, const char *buf, size_t size) +static ssize_t write_unexport(struct file *file, char *buf, size_t size) { - struct nfsctl_export data; - if (size < sizeof(data)) + struct nfsctl_export *data; + + if (size < sizeof(*data)) return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - return exp_unexport(&data); + data = (struct nfsctl_export*)buf; + return exp_unexport(data); } -static ssize_t write_getfs(struct file *file, const char *buf, size_t size) +static ssize_t write_getfs(struct file *file, char *buf, size_t size) { - struct nfsctl_fsparm data; + struct nfsctl_fsparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh *res; - if (file->private_data) + if (size < sizeof(*data)) return -EINVAL; - if (size < sizeof(data)) - return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - if (data.gd_addr.sa_family != AF_INET) - return -EPROTONOSUPPORT; - sin = (struct sockaddr_in *)&data.gd_addr; - if (data.gd_maxlen > NFS3_FHSIZE) - data.gd_maxlen = NFS3_FHSIZE; - res = kmalloc(sizeof(struct knfsd_fh), GFP_KERNEL); - if (!res) - return -ENOMEM; - memset(res, 0, sizeof(struct knfsd_fh)); + data = (struct nfsctl_fsparm*)buf; + err = -EPROTONOSUPPORT; + if (data->gd_addr.sa_family != AF_INET) + goto out; + sin = (struct sockaddr_in *)&data->gd_addr; + if (data->gd_maxlen > NFS3_FHSIZE) + data->gd_maxlen = NFS3_FHSIZE; + + res = (struct knfsd_fh*)buf; + exp_readlock(); if (!(clp = auth_unix_lookup(sin->sin_addr))) err = -EPERM; else { - err = exp_rootfh(clp, data.gd_path, res, data.gd_maxlen); + err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); auth_domain_put(clp); } exp_readunlock(); - - down(&file->f_dentry->d_inode->i_sem); - if (file->private_data) - err = -EINVAL; - if (err) - kfree(res); - else { - file->f_dentry->d_inode->i_size = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; - file->private_data = res; - err = sizeof(data); - } - up(&file->f_dentry->d_inode->i_sem); - + if (err == 0) + err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; + out: return err; } -static ssize_t write_getfd(struct file *file, const char *buf, size_t size) +static ssize_t write_getfd(struct file *file, char *buf, size_t size) { - struct nfsctl_fdparm data; + struct nfsctl_fdparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh fh; char *res; - if (file->private_data) + if (size < sizeof(*data)) return -EINVAL; - if (size < sizeof(data)) - return -EINVAL; - if (copy_from_user(&data, buf, size)) - return -EFAULT; - if (data.gd_addr.sa_family != AF_INET) - return -EPROTONOSUPPORT; - if (data.gd_version < 2 || data.gd_version > NFSSVC_MAXVERS) - return -EINVAL; - res = kmalloc(NFS_FHSIZE, GFP_KERNEL); - if (!res) - return -ENOMEM; - sin = (struct sockaddr_in *)&data.gd_addr; + data = (struct nfsctl_fdparm*)buf; + err = -EPROTONOSUPPORT; + if (data->gd_addr.sa_family != AF_INET) + goto out; + err = -EINVAL; + if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) + goto out; + + res = buf; + sin = (struct sockaddr_in *)&data->gd_addr; exp_readlock(); if (!(clp = auth_unix_lookup(sin->sin_addr))) err = -EPERM; else { - err = exp_rootfh(clp, data.gd_path, &fh, NFS_FHSIZE); + err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); auth_domain_put(clp); } exp_readunlock(); - down(&file->f_dentry->d_inode->i_sem); - if (file->private_data) - err = -EINVAL; - if (!err && fh.fh_size > NFS_FHSIZE) - err = -EINVAL; - if (err) - kfree(res); - else { + if (err == 0) { memset(res,0, NFS_FHSIZE); memcpy(res, &fh.fh_base, fh.fh_size); - file->f_dentry->d_inode->i_size = NFS_FHSIZE; - file->private_data = res; - err = sizeof(data); + err = NFS_FHSIZE; } - up(&file->f_dentry->d_inode->i_sem); - + out: return err; } +static ssize_t write_filehandle(struct file *file, char *buf, size_t size) +{ + /* request is: + * domain path maxsize + * response is + * filehandle + * + * qword quoting is used, so filehandle will be \x.... + */ + char *dname, *path; + int maxsize; + char *mesg = buf; + int len; + struct auth_domain *dom; + struct knfsd_fh fh; + + if (buf[size-1] != '\n') + return -EINVAL; + buf[size-1] = 0; + + dname = mesg; + len = qword_get(&mesg, dname, size); + if (len <= 0) return -EINVAL; + + path = dname+len+1; + len = qword_get(&mesg, path, size); + if (len <= 0) return -EINVAL; + + len = get_int(&mesg, &maxsize); + if (len) + return len; + + if (maxsize < NFS_FHSIZE) + return -EINVAL; + if (maxsize > NFS3_FHSIZE) + maxsize = NFS3_FHSIZE; + + if (qword_get(&mesg, mesg, size)>0) + return -EINVAL; + + /* we have all the words, they are in buf.. */ + dom = unix_domain_find(dname); + if (!dom) + return -ENOMEM; + + len = exp_rootfh(dom, path, &fh, maxsize); + auth_domain_put(dom); + if (len) + return len; + + mesg = buf; len = PAGE_SIZE-sizeof(struct argresp); + qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); + mesg[-1] = '\n'; + return mesg - buf; +} + +extern int nfsd_nrthreads(void); + +static ssize_t write_threads(struct file *file, char *buf, size_t size) +{ + /* if size > 0, look for a number of threads and call nfsd_svc + * then write out number of threads as reply + */ + char *mesg = buf; + int rv; + if (size > 0) { + int newthreads; + rv = get_int(&mesg, &newthreads); + if (rv) + return rv; + if (newthreads <0) + return -EINVAL; + rv = nfsd_svc(2049, newthreads); + if (rv) + return rv; + } + sprintf(buf, "%d\n", nfsd_nrthreads()); + return strlen(buf); +} + /*----------------------------------------------------------------------------*/ /* * populating the filesystem. @@ -357,7 +462,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) iput(inode); return -ENOMEM; } - for (i = NFSD_Svc; i <= NFSD_List; i++) { + for (i = NFSD_Svc; i < NFSD_END; i++) { struct qstr name; name.name = files[i].name; name.len = strlen(name.name); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 1c50df32422b..78ead0520d8b 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -146,11 +146,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) } error = nfserr_dropit; - if (IS_ERR(exp)) + if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) goto out; error = nfserr_stale; - if (!exp) + if (!exp || IS_ERR(exp)) goto out; /* Check if the request originated from a secure port. */ diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index da4271183ef7..94f48ae35e95 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -66,6 +66,14 @@ struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); */ #define NFSD_MAXSERVS 8192 +int nfsd_nrthreads(void) +{ + if (nfsd_serv == NULL) + return 0; + else + return nfsd_serv->sv_nrthreads; +} + int nfsd_svc(unsigned short port, int nrservs) { diff --git a/fs/readdir.c b/fs/readdir.c index 74c0588af131..851091637310 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -11,6 +11,7 @@ #include <linux/file.h> #include <linux/smp_lock.h> #include <linux/fs.h> +#include <linux/dirent.h> #include <linux/security.h> #include <asm/uaccess.h> @@ -194,17 +195,6 @@ out: return error; } -/* - * And even better one including d_type field and 64bit d_ino and d_off. - */ -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[0]; -}; - #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) struct getdents_callback64 { diff --git a/include/asm-alpha/module.h b/include/asm-alpha/module.h index edd833ab79dd..e2b59f65535c 100644 --- a/include/asm-alpha/module.h +++ b/include/asm-alpha/module.h @@ -1,6 +1,23 @@ -#ifndef _ASM_ALPHA_MODULE_H -#define _ASM_ALPHA_MODULE_H +#ifndef _ALPHA_MODULE_H +#define _ALPHA_MODULE_H -/* Module rewrite still in progress. */ +struct mod_arch_specific +{ + unsigned int gotsecindex; +}; -#endif /* _ASM_ALPHA_MODULE_H */ +#define Elf_Sym Elf64_Sym +#define Elf_Shdr Elf64_Shdr +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Dyn Elf64_Dyn +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela + +#define ARCH_SHF_SMALL SHF_ALPHA_GPREL + +#ifdef MODULE +asm(".section .got,\"aws\",@nobits; .align 3; .previous"); +#endif + +#endif /*_ALPHA_MODULE_H*/ diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h index 5a3b8681f6af..a5985281aa7f 100644 --- a/include/asm-alpha/uaccess.h +++ b/include/asm-alpha/uaccess.h @@ -501,19 +501,14 @@ struct exception_table_entry } fixup; }; -/* Returns 0 if exception not found and fixup.unit otherwise. */ -extern unsigned search_exception_table(unsigned long); - /* Returns the new pc */ -#define fixup_exception(map_reg, fixup_unit, pc) \ +#define fixup_exception(map_reg, fixup, pc) \ ({ \ - union exception_fixup __fie_fixup; \ - __fie_fixup.unit = fixup_unit; \ - if (__fie_fixup.bits.valreg != 31) \ - map_reg(__fie_fixup.bits.valreg) = 0; \ - if (__fie_fixup.bits.errreg != 31) \ - map_reg(__fie_fixup.bits.errreg) = -EFAULT; \ - (pc) + __fie_fixup.bits.nextinsn; \ + if ((fixup)->fixup.bits.valreg != 31) \ + map_reg((fixup)->fixup.bits.valreg) = 0; \ + if ((fixup)->fixup.bits.errreg != 31) \ + map_reg((fixup)->fixup.bits.errreg) = -EFAULT; \ + (pc) + (fixup)->fixup.bits.nextinsn; \ }) diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h index 0c054078731b..a143e85d521e 100644 --- a/include/asm-i386/highmem.h +++ b/include/asm-i386/highmem.h @@ -39,7 +39,7 @@ extern void kmap_init(void); * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#define PKMAP_BASE (0xfe000000UL) +#define PKMAP_BASE (0xff800000UL) #ifdef CONFIG_X86_PAE #define LAST_PKMAP 512 #else diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 1bf8d4830649..adcd9a41c7d2 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -110,6 +110,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ +#define TIF_IRET 5 /* return with iret */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ @@ -118,6 +119,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) +#define _TIF_IRET (1<<TIF_IRET) #define _TIF_USEDFPU (1<<TIF_USEDFPU) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 377038170a0b..ef7f1101a94c 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -92,10 +92,6 @@ struct exception_table_entry unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - - /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h index 1931d72ce8a9..51bb269cf589 100644 --- a/include/asm-ppc/uaccess.h +++ b/include/asm-ppc/uaccess.h @@ -56,8 +56,6 @@ struct exception_table_entry unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); extern void sort_exception_table(void); /* diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h index f384c300e5e3..bf8792ec92bb 100644 --- a/include/asm-sparc64/compat.h +++ b/include/asm-sparc64/compat.h @@ -5,32 +5,25 @@ */ #include <linux/types.h> -#define COMPAT_USER_HZ 100 +#define COMPAT_USER_HZ 100 typedef u32 compat_size_t; typedef s32 compat_ssize_t; typedef s32 compat_time_t; typedef s32 compat_clock_t; - -struct compat_stat { - __kernel_dev_t32 st_dev; - __kernel_ino_t32 st_ino; - __kernel_mode_t32 st_mode; - s16 st_nlink; - __kernel_uid_t32 st_uid; - __kernel_gid_t32 st_gid; - __kernel_dev_t32 st_rdev; - __kernel_off_t32 st_size; - compat_time_t st_atime; - u32 __unused1; - compat_time_t st_mtime; - u32 __unused2; - compat_time_t st_ctime; - u32 __unused3; - __kernel_off_t32 st_blksize; - __kernel_off_t32 st_blocks; - u32 __unused4[2]; -}; +typedef s32 compat_pid_t; +typedef u16 compat_uid_t; +typedef u16 compat_gid_t; +typedef u16 compat_mode_t; +typedef u32 compat_ino_t; +typedef u16 compat_dev_t; +typedef s32 compat_off_t; +typedef s64 compat_loff_t; +typedef s16 compat_nlink_t; +typedef u16 compat_ipc_pid_t; +typedef s32 compat_daddr_t; +typedef u32 compat_caddr_t; +typedef __kernel_fsid_t compat_fsid_t; struct compat_timespec { compat_time_t tv_sec; @@ -42,13 +35,33 @@ struct compat_timeval { s32 tv_usec; }; +struct compat_stat { + compat_dev_t st_dev; + compat_ino_t st_ino; + compat_mode_t st_mode; + compat_nlink_t st_nlink; + compat_uid_t st_uid; + compat_gid_t st_gid; + compat_dev_t st_rdev; + compat_off_t st_size; + compat_time_t st_atime; + u32 __unused1; + compat_time_t st_mtime; + u32 __unused2; + compat_time_t st_ctime; + u32 __unused3; + compat_off_t st_blksize; + compat_off_t st_blocks; + u32 __unused4[2]; +}; + struct compat_flock { - short l_type; - short l_whence; - __kernel_off_t32 l_start; - __kernel_off_t32 l_len; - __kernel_pid_t32 l_pid; - short __unused; + short l_type; + short l_whence; + compat_off_t l_start; + compat_off_t l_len; + compat_pid_t l_pid; + short __unused; }; #endif /* _ASM_SPARC64_COMPAT_H */ diff --git a/include/asm-sparc64/posix_types.h b/include/asm-sparc64/posix_types.h index dee9441f02d7..b39c8781fb7e 100644 --- a/include/asm-sparc64/posix_types.h +++ b/include/asm-sparc64/posix_types.h @@ -47,23 +47,6 @@ typedef struct { #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ } __kernel_fsid_t; -/* Now 32bit compatibility types */ -typedef int __kernel_ptrdiff_t32; -typedef int __kernel_pid_t32; -typedef unsigned short __kernel_ipc_pid_t32; -typedef unsigned short __kernel_uid_t32; -typedef unsigned short __kernel_gid_t32; -typedef unsigned short __kernel_dev_t32; -typedef unsigned int __kernel_ino_t32; -typedef unsigned short __kernel_mode_t32; -typedef unsigned short __kernel_umode_t32; -typedef short __kernel_nlink_t32; -typedef int __kernel_daddr_t32; -typedef int __kernel_off_t32; -typedef unsigned int __kernel_caddr_t32; -typedef long __kernel_loff_t32; -typedef __kernel_fsid_t __kernel_fsid_t32; - #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) #undef __FD_SET diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h index 5104c270ca25..72289f69991b 100644 --- a/include/asm-sparc64/siginfo.h +++ b/include/asm-sparc64/siginfo.h @@ -13,7 +13,7 @@ #ifdef __KERNEL__ -#include <asm/compat.h> +#include <linux/compat.h> typedef union sigval32 { int sival_int; @@ -30,7 +30,7 @@ typedef struct siginfo32 { /* kill() */ struct { - __kernel_pid_t32 _pid; /* sender's pid */ + compat_pid_t _pid; /* sender's pid */ unsigned int _uid; /* sender's uid */ } _kill; @@ -42,14 +42,14 @@ typedef struct siginfo32 { /* POSIX.1b signals */ struct { - __kernel_pid_t32 _pid; /* sender's pid */ + compat_pid_t _pid; /* sender's pid */ unsigned int _uid; /* sender's uid */ sigval_t32 _sigval; } _rt; /* SIGCHLD */ struct { - __kernel_pid_t32 _pid; /* which child */ + compat_pid_t _pid; /* which child */ unsigned int _uid; /* sender's uid */ int _status; /* exit code */ compat_clock_t _utime; diff --git a/include/asm-sparc64/statfs.h b/include/asm-sparc64/statfs.h index 5aee11569fbd..116ae1814702 100644 --- a/include/asm-sparc64/statfs.h +++ b/include/asm-sparc64/statfs.h @@ -5,6 +5,7 @@ #ifndef __KERNEL_STRICT_NAMES #include <linux/types.h> +#include <linux/compat.h> /* for compat_fsid_t */ typedef __kernel_fsid_t fsid_t; @@ -18,7 +19,7 @@ struct statfs32 { int f_bavail; int f_files; int f_ffree; - __kernel_fsid_t32 f_fsid; + compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ int f_spare[6]; }; diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h index 5d9b9d4a070a..3f04ac105de9 100644 --- a/include/asm-sparc64/uaccess.h +++ b/include/asm-sparc64/uaccess.h @@ -84,8 +84,8 @@ struct exception_table_entry unsigned insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long, unsigned long *); +/* Special exable search, which handles ranges. Returns fixup */ +unsigned long search_extables_range(unsigned long addr, unsigned long *g2); extern void __ret_efault(void); diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index 90890f4e9e6d..e8fec2776624 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -63,7 +63,7 @@ enum chipset_type { VIA_APOLLO_KT400_3, VIA_APOLLO_PRO_266, VIA_VT8605, - VIA_P4X400, + VIA_P4X, SIS_GENERIC, AMD_GENERIC, AMD_IRONGATE, diff --git a/include/linux/dirent.h b/include/linux/dirent.h index bef1120cba96..5d6023b87800 100644 --- a/include/linux/dirent.h +++ b/include/linux/dirent.h @@ -16,4 +16,17 @@ struct dirent64 { char d_name[256]; }; +#ifdef __KERNEL__ + +struct linux_dirent64 { + u64 d_ino; + s64 d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +}; + +#endif /* __KERNEL__ */ + + #endif diff --git a/include/linux/elf.h b/include/linux/elf.h index 2745227ff929..4435d0be3575 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -159,6 +159,9 @@ typedef __s64 Elf64_Sxword; #define ELF32_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF64_ST_BIND(x) ((x) >> 4) +#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf) + /* Symbolic values for the entries in the auxiliary table put on the initial stack */ #define AT_NULL 0 /* end of vector */ @@ -362,22 +365,30 @@ typedef struct { #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_OP_PUSH 12 /* OP stack push */ -#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ -#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ -#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ -#define R_ALPHA_GPVALUE 16 -#define R_ALPHA_GPRELHIGH 17 -#define R_ALPHA_GPRELLOW 18 -#define R_ALPHA_IMMED_GP_16 19 -#define R_ALPHA_IMMED_GP_HI32 20 -#define R_ALPHA_IMMED_SCN_HI32 21 -#define R_ALPHA_IMMED_BR_HI32 22 -#define R_ALPHA_IMMED_LO32 23 +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_BRSGP 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define SHF_ALPHA_GPREL 0x10000000 + /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 1586beac00fb..b8334a2df0d8 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -14,8 +14,6 @@ extern struct page *highmem_start_page; /* declarations for linux/mm/highmem.c */ unsigned int nr_free_highpages(void); -extern void check_highmem_ptes(void); - #else /* CONFIG_HIGHMEM */ static inline unsigned int nr_free_highpages(void) { return 0; } @@ -30,6 +28,13 @@ static inline void *kmap(struct page *page) { return page_address(page); } #endif /* CONFIG_HIGHMEM */ +#if defined(CONFIG_DEBUG_HIGHMEM) && defined(CONFIG_HIGHMEM) +extern void check_highmem_ptes(void); +#else +static inline void check_highmem_ptes(void) +{} +#endif + /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { diff --git a/include/linux/init.h b/include/linux/init.h index b7c6363478aa..a3ad7dd1a38f 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -111,7 +111,8 @@ struct obs_kernel_param { * * module_init() will either be called during do_initcalls (if * builtin) or at module insertion time (if a module). There can only - * be one per module. */ + * be one per module. + */ #define module_init(x) __initcall(x); /** diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 9cb6277f5b86..7eedbb751856 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -84,6 +84,7 @@ extern unsigned long long memparse(char *ptr, char **retptr); extern void dev_probe_lock(void); extern void dev_probe_unlock(void); +extern int kernel_text_address(unsigned long addr); extern int session_of_pgrp(int pgrp); asmlinkage int printk(const char * fmt, ...) @@ -105,7 +106,7 @@ extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in extern int tainted; extern const char *print_tainted(void); -#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_PROPRIETARY_MODULE (1<<0) #define TAINT_FORCED_MODULE (1<<1) #define TAINT_UNSAFE_SMP (1<<2) #define TAINT_FORCED_RMMOD (1<<3) diff --git a/include/linux/module.h b/include/linux/module.h index 8e1954a89913..54214da9a651 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -21,7 +21,6 @@ #include <asm/uaccess.h> /* For struct exception_table_entry */ /* Not Yet Implemented */ -#define MODULE_LICENSE(name) #define MODULE_AUTHOR(name) #define MODULE_DESCRIPTION(desc) #define MODULE_SUPPORTED_DEVICE(name) @@ -44,6 +43,12 @@ struct kernel_symbol extern int init_module(void); extern void cleanup_module(void); +/* Archs provide a method of finding the correct exception table. */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value); + #ifdef MODULE /* For replacement modutils, use an alias not a pointer. */ @@ -57,11 +62,41 @@ extern const struct gtype##_id __mod_##gtype##_table \ #define THIS_MODULE (&__this_module) +/* + * The following license idents are currently accepted as indicating free + * software modules + * + * "GPL" [GNU Public License v2 or later] + * "GPL v2" [GNU Public License v2] + * "GPL and additional rights" [GNU Public License v2 rights and more] + * "Dual BSD/GPL" [GNU Public License v2 + * or BSD license choice] + * "Dual MPL/GPL" [GNU Public License v2 + * or Mozilla license choice] + * + * The following other idents are available + * + * "Proprietary" [Non free products] + * + * There are dual licensed components, but when running with Linux it is the + * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL + * is a GPL combined work. + * + * This exists for several reasons + * 1. So modinfo can show license info for users wanting to vet their setup + * is free + * 2. So the community can ignore bug reports including proprietary modules + * 3. So vendors can do likewise based on their own policies + */ +#define MODULE_LICENSE(license) \ + static const char __module_license[] \ + __attribute__((section(".init.license"))) = license + #else /* !MODULE */ #define MODULE_GENERIC_TABLE(gtype,name) #define THIS_MODULE ((struct module *)0) - +#define MODULE_LICENSE(license) #endif #define MODULE_DEVICE_TABLE(type,name) \ @@ -75,10 +110,16 @@ struct kernel_symbol_group /* Module which owns it (if any) */ struct module *owner; + /* Are we internal use only? */ + int gplonly; + unsigned int num_syms; const struct kernel_symbol *syms; }; +/* Given an address, look for it in the exception tables */ +const struct exception_table_entry *search_exception_tables(unsigned long add); + struct exception_table { struct list_head list; @@ -101,7 +142,11 @@ void *__symbol_get_gpl(const char *symbol); = { (unsigned long)&sym, MODULE_SYMBOL_PREFIX #sym } #define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym) -#define EXPORT_SYMBOL_GPL(sym) EXPORT_SYMBOL(sym) + +#define EXPORT_SYMBOL_GPL(sym) \ + const struct kernel_symbol __ksymtab_##sym \ + __attribute__((section("__gpl_ksymtab"))) \ + = { (unsigned long)&sym, #sym } struct module_ref { @@ -128,6 +173,9 @@ struct module /* Exported symbols */ struct kernel_symbol_group symbols; + /* GPL-only exported symbols. */ + struct kernel_symbol_group gpl_symbols; + /* Exception tables */ struct exception_table extable; @@ -149,6 +197,9 @@ struct module /* Am I unsafe to unload? */ int unsafe; + /* Am I GPL-compatible */ + int license_gplok; + #ifdef CONFIG_MODULE_UNLOAD /* Reference counts */ struct module_ref ref[NR_CPUS]; @@ -183,6 +234,9 @@ static inline int module_is_live(struct module *mod) return mod->state != MODULE_STATE_GOING; } +/* Is this address in a module? */ +int module_text_address(unsigned long addr); + #ifdef CONFIG_MODULE_UNLOAD void __symbol_put(const char *symbol); @@ -258,18 +312,40 @@ const char *module_address_lookup(unsigned long addr, unsigned long *offset, char **modname); +/* For extable.c to search modules' exception tables. */ +const struct exception_table_entry *search_module_extables(unsigned long addr); + #else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL(sym) #define EXPORT_SYMBOL_GPL(sym) #define EXPORT_SYMBOL_NOVERS(sym) +/* Given an address, look for it in the exception tables. */ +static inline const struct exception_table_entry * +search_module_extables(unsigned long addr) +{ + return NULL; +} + +/* Is this address in a module? */ +static int module_text_address(unsigned long addr) +{ + return 0; +} + /* Get/put a kernel symbol (calls should be symmetric) */ #define symbol_get(x) (&(x)) #define symbol_put(x) do { } while(0) #define symbol_put_addr(x) do { } while(0) -#define try_module_get(module) 1 -#define module_put(module) do { } while(0) +static inline int try_module_get(struct module *module) +{ + return 1; +} + +static inline void module_put(struct module *module) +{ +} #define module_name(mod) "kernel" @@ -293,6 +369,7 @@ struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = __stringify(KBUILD_MODNAME), .symbols = { .owner = &__this_module }, + .gpl_symbols = { .owner = &__this_module, .gplonly = 1 }, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, @@ -301,10 +378,6 @@ __attribute__((section(".gnu.linkonce.this_module"))) = { #endif /* KBUILD_MODNAME */ #endif /* MODULE */ -/* For archs to search exception tables */ -extern struct list_head extables; -extern spinlock_t modlist_lock; - #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */ @@ -362,14 +435,6 @@ extern int module_dummy_usage; #define GET_USE_COUNT(module) (module_dummy_usage) #define MOD_IN_USE 0 #define __MODULE_STRING(x) __stringify(x) -#define __mod_between(a_start, a_len, b_start, b_len) \ -(((a_start) >= (b_start) && (a_start) <= (b_start)+(b_len)) \ - || ((a_start)+(a_len) >= (b_start) \ - && (a_start)+(a_len) <= (b_start)+(b_len))) -#define mod_bound(p, n, m) \ -(((m)->module_init \ - && __mod_between((p),(n),(m)->module_init,(m)->init_size)) \ - || __mod_between((p),(n),(m)->module_core,(m)->core_size)) /* * The exception and symbol tables, and the lock diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index 5001ff39204d..991e9cdf3213 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -16,9 +16,9 @@ unsigned long find_symbol_internal(Elf_Shdr *sechdrs, /* These must be implemented by the specific architecture */ /* Adjust arch-specific sections. Return 0 on success. */ -int module_frob_arch_sections(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, struct module *mod); /* Allocator used for allocating struct module, core sections and init diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 8359679908ab..c29972812936 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -320,6 +320,7 @@ struct nfsd4_compoundres { u32 taglen; char * tag; u32 opcnt; + u32 * tagp; /* where to encode tag and opcount */ }; #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 9707f467b2be..1a297ca9d00a 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -66,10 +66,10 @@ extern struct page * read_cache_page(struct address_space *mapping, extern int read_cache_pages(struct address_space *mapping, struct list_head *pages, filler_t *filler, void *data); -extern int add_to_page_cache(struct page *page, - struct address_space *mapping, unsigned long index); -extern int add_to_page_cache_lru(struct page *page, - struct address_space *mapping, unsigned long index); +int add_to_page_cache(struct page *page, struct address_space *mapping, + unsigned long index, int gfp_mask); +int add_to_page_cache_lru(struct page *page, struct address_space *mapping, + unsigned long index, int gfp_mask); extern void remove_from_page_cache(struct page *page); extern void __remove_from_page_cache(struct page *page); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 89874d8eeee7..0cab668cbfc6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1092,7 +1092,7 @@ #define PCI_DEVICE_ID_VIA_8233C_0 0x3109 #define PCI_DEVICE_ID_VIA_8361 0x3112 #define PCI_DEVICE_ID_VIA_8233A 0x3147 -#define PCI_DEVICE_ID_VIA_8235_0 0x3168 +#define PCI_DEVICE_ID_VIA_8754 0x3168 #define PCI_DEVICE_ID_VIA_8235 0x3177 #define PCI_DEVICE_ID_VIA_8377_0 0x3189 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 4e58eb79abeb..f4a78d52b5ce 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -19,6 +19,8 @@ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H +#include <linux/preempt.h> + struct radix_tree_node; struct radix_tree_root { @@ -45,5 +47,11 @@ extern int radix_tree_delete(struct radix_tree_root *, unsigned long); extern unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); +int radix_tree_preload(int gfp_mask); + +static inline void radix_tree_preload_end(void) +{ + preempt_enable(); +} #endif /* _LINUX_RADIX_TREE_H */ diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index f658735d28b2..d6f2928fc8c7 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -28,6 +28,8 @@ #define LEVEL_MULTIPATH (-4) #define LEVEL_LINEAR (-1) +#define MaxSector (~(sector_t)0) + static inline int pers_to_level (int pers) { switch (pers) { @@ -198,7 +200,6 @@ struct mddev_s int level, layout; int raid_disks; int max_disks; - unsigned long state; sector_t size; /* used size of component devices */ __u64 events; @@ -215,6 +216,7 @@ struct mddev_s * it can only be set > 0 under reconfig_sem */ int recovery_running; + int recovery_error; /* error from recovery write */ int in_sync; /* know to not need resync */ struct semaphore reconfig_sem; atomic_t active; @@ -226,6 +228,7 @@ struct mddev_s atomic_t recovery_active; /* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; + sector_t recovery_cp; request_queue_t queue; /* for plugging ... */ diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index d6bb37a810b3..cb002ba3556f 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -131,11 +131,16 @@ typedef struct mdp_superblock_s { #ifdef __BIG_ENDIAN __u32 events_hi; /* 7 high-order of superblock update count */ __u32 events_lo; /* 8 low-order of superblock update count */ + __u32 cp_events_hi; /* 9 high-order of checkpoint update count */ + __u32 cp_events_lo; /* 10 low-order of checkpoint update count */ #else __u32 events_lo; /* 7 low-order of superblock update count */ __u32 events_hi; /* 8 high-order of superblock update count */ + __u32 cp_events_lo; /* 9 low-order of checkpoint update count */ + __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ #endif - __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 9]; + __u32 recovery_cp; /* 11 recovery checkpoint sector count */ + __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 12]; /* * Personality information diff --git a/include/linux/rmap-locking.h b/include/linux/rmap-locking.h index 302a58f54ca3..51f6697f3794 100644 --- a/include/linux/rmap-locking.h +++ b/include/linux/rmap-locking.h @@ -5,6 +5,11 @@ * pte chain. */ +#include <linux/slab.h> + +struct pte_chain; +extern kmem_cache_t *pte_chain_cache; + static inline void pte_chain_lock(struct page *page) { /* @@ -31,3 +36,12 @@ static inline void pte_chain_unlock(struct page *page) #endif preempt_enable(); } + +struct pte_chain *pte_chain_alloc(int gfp_flags); +void __pte_chain_free(struct pte_chain *pte_chain); + +static inline void pte_chain_free(struct pte_chain *pte_chain) +{ + if (pte_chain) + __pte_chain_free(pte_chain); +} diff --git a/include/linux/smp.h b/include/linux/smp.h index 8243c6bec130..06ac1c4f1530 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -86,6 +86,7 @@ int cpu_up(unsigned int cpu); void smp_prepare_boot_cpu(void); #else /* !SMP */ +#include <asm/page.h> /* For BUG() */ /* * These macros fold the SMP functionality into a single CPU system diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 74e53a04907e..a3cdc080dd85 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -78,6 +78,11 @@ struct cache_detail { int (*cache_parse)(struct cache_detail *, char *buf, int len); + int (*cache_show)(struct seq_file *m, + struct cache_detail *cd, + struct cache_head *h, + char *pbuf); + /* fields below this comment are for internal use * and should not be touched by cache owners */ @@ -171,7 +176,7 @@ RTN *FNAME ARGS \ if (!new) break; \ \ new->MEMBER.next = tmp->MEMBER.next; \ - *head = &new->MEMBER; \ + *hp = &new->MEMBER; \ tmp->MEMBER.next = NULL; \ set_bit(CACHE_HASHED, &new->MEMBER.flags); \ clear_bit(CACHE_HASHED, &tmp->MEMBER.flags); \ diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 9c6bf43a26b8..95a45edc2f99 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -11,8 +11,10 @@ #ifdef __KERNEL__ +#include <linux/string.h> #include <linux/sunrpc/msg_prot.h> #include <linux/sunrpc/cache.h> +#include <linux/string.h> struct svc_cred { uid_t cr_uid; @@ -111,7 +113,11 @@ extern struct auth_domain *auth_unix_lookup(struct in_addr addr); extern int auth_unix_forget_old(struct auth_domain *dom); extern void svcauth_unix_purge(void); -extern int name_hash(char *name, int size); +extern int hash_mem(char *buf, int len, int bits); +static inline int hash_str(char *name, int bits) +{ + return hash_mem(name, strlen(name), bits); +} extern struct cache_detail auth_domain_cache, ip_map_cache; diff --git a/include/linux/swap.h b/include/linux/swap.h index 9ab02098aad5..d20061e6cb08 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -169,11 +169,13 @@ extern int vm_swappiness; extern void out_of_memory(void); /* linux/mm/rmap.c */ -extern int FASTCALL(page_referenced(struct page *)); -extern void FASTCALL(page_add_rmap(struct page *, pte_t *)); -extern void FASTCALL(page_remove_rmap(struct page *, pte_t *)); -extern int FASTCALL(try_to_unmap(struct page *)); -extern int FASTCALL(page_over_rsslimit(struct page *)); +struct pte_chain; +int FASTCALL(page_referenced(struct page *)); +struct pte_chain *FASTCALL(page_add_rmap(struct page *, pte_t *, + struct pte_chain *)); +void FASTCALL(page_remove_rmap(struct page *, pte_t *)); +int FASTCALL(try_to_unmap(struct page *)); +int FASTCALL(page_over_rsslimit(struct page *)); /* return values of try_to_unmap */ #define SWAP_SUCCESS 0 diff --git a/init/Kconfig b/init/Kconfig index 962d16696ef9..2868e39049c0 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -82,6 +82,51 @@ config SYSCTL building a kernel for install/rescue disks or your system is very limited in memory. +choice + prompt "Kernel log buffer size" + default LOG_BUF_SHIFT_17 if ARCH_S390 + default LOG_BUF_SHIFT_16 if X86_NUMAQ || IA64 + default LOG_BUF_SHIFT_15 if SMP + default LOG_BUF_SHIFT_14 + help + Select kernel log buffer size from this list (power of 2). + Defaults: 17 (=> 128 KB for S/390) + 16 (=> 64 KB for x86 NUMAQ or IA-64) + 15 (=> 32 KB for SMP) + 14 (=> 16 KB for uniprocessor) + +config LOG_BUF_SHIFT_17 + bool "128 KB" + default y if ARCH_S390 + +config LOG_BUF_SHIFT_16 + bool "64 KB" + default y if X86_NUMAQ || IA64 + +config LOG_BUF_SHIFT_15 + bool "32 KB" + default y if SMP + +config LOG_BUF_SHIFT_14 + bool "16 KB" + +config LOG_BUF_SHIFT_13 + bool "8 KB" + +config LOG_BUF_SHIFT_12 + bool "4 KB" + +endchoice + +config LOG_BUF_SHIFT + int + default 17 if LOG_BUF_SHIFT_17=y + default 16 if LOG_BUF_SHIFT_16=y + default 15 if LOG_BUF_SHIFT_15=y + default 14 if LOG_BUF_SHIFT_14=y + default 13 if LOG_BUF_SHIFT_13=y + default 12 if LOG_BUF_SHIFT_12=y + endmenu diff --git a/init/do_mounts.c b/init/do_mounts.c index d66050501009..316e29d758d3 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -13,6 +13,7 @@ #include <linux/suspend.h> #include <linux/root_dev.h> #include <linux/mount.h> +#include <linux/dirent.h> #include <linux/security.h> #include <linux/nfs_fs.h> @@ -324,22 +325,32 @@ static int __init mount_nfs_root(void) #endif #ifdef CONFIG_DEVFS_FS + +/* + * If the dir will fit in *buf, return its length. If it won't fit, return + * zero. Return -ve on error. + */ static int __init do_read_dir(int fd, void *buf, int len) { long bytes, n; char *p = buf; lseek(fd, 0, 0); - for (bytes = 0, p = buf; bytes < len; bytes += n, p+=n) { - n = sys_getdents64(fd, p, len - bytes); + for (bytes = 0; bytes < len; bytes += n) { + n = sys_getdents64(fd, p + bytes, len - bytes); if (n < 0) - return -1; + return n; if (n == 0) return bytes; } return 0; } +/* + * Try to read all of a directory. Returns the contents at *p, which + * is kmalloced memory. Returns the number of bytes read at *len. Returns + * NULL on error. + */ static void * __init read_dir(char *path, int *len) { int size; @@ -349,7 +360,7 @@ static void * __init read_dir(char *path, int *len) if (fd < 0) return NULL; - for (size = 1<<9; size < (1<<18); size <<= 1) { + for (size = 1 << 9; size <= (1 << MAX_ORDER); size <<= 1) { void *p = kmalloc(size, GFP_KERNEL); int n; if (!p) @@ -361,6 +372,8 @@ static void * __init read_dir(char *path, int *len) return p; } kfree(p); + if (n == -EINVAL) + continue; /* Try a larger buffer */ if (n < 0) break; } @@ -369,14 +382,6 @@ static void * __init read_dir(char *path, int *len) } #endif -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[0]; -}; - static int __init find_in_devfs(char *path, dev_t dev) { #ifdef CONFIG_DEVFS_FS diff --git a/init/main.c b/init/main.c index b07fac4e9f02..ec70f2fa704c 100644 --- a/init/main.c +++ b/init/main.c @@ -58,16 +58,15 @@ extern char *linux_banner; static int init(void *); extern void init_IRQ(void); -extern void init_modules(void); extern void sock_init(void); extern void fork_init(unsigned long); -extern void extable_init(void); extern void mca_init(void); extern void sbus_init(void); extern void sysctl_init(void); extern void signals_init(void); extern void buffer_init(void); extern void pidhash_init(void); +extern void pidmap_init(void); extern void pte_chain_init(void); extern void radix_tree_init(void); extern void free_initmem(void); @@ -391,9 +390,9 @@ asmlinkage void __init start_kernel(void) &__stop___param - &__start___param, &unknown_bootoption); trap_init(); - extable_init(); rcu_init(); init_IRQ(); + pidhash_init(); sched_init(); softirq_init(); time_init(); @@ -419,7 +418,7 @@ asmlinkage void __init start_kernel(void) page_address_init(); mem_init(); kmem_cache_sizes_init(); - pidhash_init(); + pidmap_init(); pgtable_cache_init(); pte_chain_init(); fork_init(num_physpages); diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c index 5dff6da1a73f..c0be78462c81 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -927,17 +927,27 @@ EXPORT_SYMBOL(cpufreq_set_policy); * adjust_jiffies - adjust the system "loops_per_jiffy" * * This function alters the system "loops_per_jiffy" for the clock - * speed change. Note that loops_per_jiffy is only updated if all - * CPUs are affected - else there is a need for per-CPU loops_per_jiffy - * values which are provided by various architectures. + * speed change. Note that loops_per_jiffy cannot be updated on SMP + * systems as each CPU might be scaled differently. So, use the arch + * per-CPU loops_per_jiffy value wherever possible. */ +#ifndef CONFIG_SMP +static unsigned long l_p_j_ref = 0; +static unsigned int l_p_j_ref_freq = 0; + static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { + if (!l_p_j_ref_freq) { + l_p_j_ref = loops_per_jiffy; + l_p_j_ref_freq = ci->old; + } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || (val == CPUFREQ_POSTCHANGE && ci->old > ci->new)) - if (ci->cpu == CPUFREQ_ALL_CPUS) - loops_per_jiffy = cpufreq_scale(loops_per_jiffy, ci->old, ci->new); + loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); } +#else +#define adjust_jiffies(...) +#endif /** diff --git a/kernel/extable.c b/kernel/extable.c index e26ef5349d23..388995324d1c 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -16,36 +16,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> -#include <linux/init.h> - -#include <asm/semaphore.h> extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; -extern const struct kernel_symbol __start___ksymtab[]; -extern const struct kernel_symbol __stop___ksymtab[]; - -/* Protects extables and symbol tables */ -spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED; - -/* The exception and symbol tables: start with kernel only. */ -LIST_HEAD(extables); -LIST_HEAD(symbols); - -static struct exception_table kernel_extable; -static struct kernel_symbol_group kernel_symbols; +extern char _stext[], _etext[]; -void __init extable_init(void) +/* Given an address, look for it in the exception tables. */ +const struct exception_table_entry *search_exception_tables(unsigned long addr) { - /* Add kernel symbols to symbol table */ - kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab); - kernel_symbols.syms = __start___ksymtab; - list_add(&kernel_symbols.list, &symbols); - - /* Add kernel exception table to exception tables */ - kernel_extable.num_entries = (__stop___ex_table -__start___ex_table); - kernel_extable.entry = __start___ex_table; - list_add(&kernel_extable.list, &extables); + const struct exception_table_entry *e; + + e = search_extable(__start___ex_table, __stop___ex_table-1, addr); + if (!e) + e = search_module_extables(addr); + return e; } +int kernel_text_address(unsigned long addr) +{ + if (addr >= (unsigned long)_stext && + addr <= (unsigned long)_etext) + return 1; + return module_text_address(addr); +} diff --git a/kernel/module.c b/kernel/module.c index ff961f21135f..bd289a331692 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -51,9 +51,14 @@ #define symbol_is(literal, string) \ (strcmp(MODULE_SYMBOL_PREFIX literal, (string)) == 0) -/* List of modules, protected by module_mutex */ +/* Protects extables and symbols lists */ +static spinlock_t modlist_lock = SPIN_LOCK_UNLOCKED; + +/* List of modules, protected by module_mutex AND modlist_lock */ static DECLARE_MUTEX(module_mutex); -LIST_HEAD(modules); /* FIXME: Accessed w/o lock on oops by some archs */ +static LIST_HEAD(modules); +static LIST_HEAD(symbols); +static LIST_HEAD(extables); /* We require a truly strong try_module_get() */ static inline int strong_try_module_get(struct module *mod) @@ -72,13 +77,16 @@ EXPORT_SYMBOL(init_module); /* Find a symbol, return value and the symbol group */ static unsigned long __find_symbol(const char *name, - struct kernel_symbol_group **group) + struct kernel_symbol_group **group, + int gplok) { struct kernel_symbol_group *ks; list_for_each_entry(ks, &symbols, list) { unsigned int i; + if (ks->gplonly && !gplok) + continue; for (i = 0; i < ks->num_syms; i++) { if (strcmp(ks->syms[i].name, name) == 0) { *group = ks; @@ -481,19 +489,29 @@ sys_delete_module(const char *name_user, unsigned int flags) static void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; + int printed_something = 0; - seq_printf(m, " %u", module_refcount(mod)); + seq_printf(m, " %u ", module_refcount(mod)); - list_for_each_entry(use, &mod->modules_which_use_me, list) - seq_printf(m, " %s", use->module_which_uses->name); + /* Always include a trailing , so userspace can differentiate + between this and the old multi-field proc format. */ + list_for_each_entry(use, &mod->modules_which_use_me, list) { + printed_something = 1; + seq_printf(m, "%s,", use->module_which_uses->name); + } - if (mod->unsafe) - seq_printf(m, " [unsafe]"); + if (mod->unsafe) { + printed_something = 1; + seq_printf(m, "[unsafe],"); + } - if (mod->init != init_module && mod->exit == cleanup_module) - seq_printf(m, " [permanent]"); + if (mod->init != init_module && mod->exit == cleanup_module) { + printed_something = 1; + seq_printf(m, "[permanent],"); + } - seq_printf(m, "\n"); + if (!printed_something) + seq_printf(m, "-"); } void __symbol_put(const char *symbol) @@ -502,7 +520,7 @@ void __symbol_put(const char *symbol) unsigned long flags; spin_lock_irqsave(&modlist_lock, flags); - if (!__find_symbol(symbol, &ksg)) + if (!__find_symbol(symbol, &ksg, 1)) BUG(); module_put(ksg->owner); spin_unlock_irqrestore(&modlist_lock, flags); @@ -534,7 +552,8 @@ EXPORT_SYMBOL_GPL(symbol_put_addr); #else /* !CONFIG_MODULE_UNLOAD */ static void print_unload_info(struct seq_file *m, struct module *mod) { - seq_printf(m, "\n"); + /* We don't know the usage count, or what modules are using. */ + seq_printf(m, " - -"); } static inline void module_unload_free(struct module *mod) @@ -721,7 +740,7 @@ unsigned long find_symbol_internal(Elf_Shdr *sechdrs, } /* Look in other modules... */ spin_lock_irq(&modlist_lock); - ret = __find_symbol(name, ksg); + ret = __find_symbol(name, ksg, mod->license_gplok); if (ret) { /* This can fail due to OOM, or module unloading */ if (!use_module(mod, (*ksg)->owner)) @@ -735,9 +754,10 @@ unsigned long find_symbol_internal(Elf_Shdr *sechdrs, static void free_module(struct module *mod) { /* Delete from various lists */ - list_del(&mod->list); spin_lock_irq(&modlist_lock); + list_del(&mod->list); list_del(&mod->symbols.list); + list_del(&mod->gpl_symbols.list); list_del(&mod->extable.list); spin_unlock_irq(&modlist_lock); @@ -758,7 +778,7 @@ void *__symbol_get(const char *symbol) unsigned long value, flags; spin_lock_irqsave(&modlist_lock, flags); - value = __find_symbol(symbol, &ksg); + value = __find_symbol(symbol, &ksg, 1); if (value && !strong_try_module_get(ksg->owner)) value = 0; spin_unlock_irqrestore(&modlist_lock, flags); @@ -930,7 +950,34 @@ static void layout_sections(struct module *mod, } } -/* Allocate and load the module */ +static inline int license_is_gpl_compatible(const char *license) +{ + return (strcmp(license, "GPL") == 0 + || strcmp(license, "GPL v2") == 0 + || strcmp(license, "GPL and additional rights") == 0 + || strcmp(license, "Dual BSD/GPL") == 0 + || strcmp(license, "Dual MPL/GPL") == 0); +} + +static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx) +{ + char *license; + + if (licenseidx) + license = (char *)sechdrs[licenseidx].sh_addr; + else + license = "unspecified"; + + mod->license_gplok = license_is_gpl_compatible(license); + if (!mod->license_gplok) { + printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", + mod->name, license); + tainted |= TAINT_PROPRIETARY_MODULE; + } +} + +/* Allocate and load the module: note that size of section 0 is always + zero, and we rely on this for optional sections. */ static struct module *load_module(void *umod, unsigned long len, const char *uargs) @@ -939,7 +986,7 @@ static struct module *load_module(void *umod, Elf_Shdr *sechdrs; char *secstrings, *args; unsigned int i, symindex, exportindex, strindex, setupindex, exindex, - modindex, obsparmindex; + modindex, obsparmindex, licenseindex, gplindex; long arglen; struct module *mod; long err = 0; @@ -975,7 +1022,7 @@ static struct module *load_module(void *umod, /* May not export symbols, or have setup params, so these may not exist */ - exportindex = setupindex = obsparmindex = 0; + exportindex = setupindex = obsparmindex = gplindex = licenseindex = 0; /* And these should exist, but gcc whinges if we don't init them */ symindex = strindex = exindex = modindex = 0; @@ -1018,6 +1065,16 @@ static struct module *load_module(void *umod, /* Obsolete MODULE_PARM() table */ DEBUGP("Obsolete param found in section %u\n", i); obsparmindex = i; + } else if (strcmp(secstrings+sechdrs[i].sh_name,".init.license") + == 0) { + /* MODULE_LICENSE() */ + DEBUGP("Licence found in section %u\n", i); + licenseindex = i; + } else if (strcmp(secstrings+sechdrs[i].sh_name, + "__gpl_ksymtab") == 0) { + /* EXPORT_SYMBOL_GPL() */ + DEBUGP("GPL symbols found in section %u\n", i); + gplindex = i; } #ifdef CONFIG_KALLSYMS /* symbol and string tables for decoding later. */ @@ -1113,17 +1170,21 @@ static struct module *load_module(void *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); + /* Set up license info based on contents of section */ + set_license(mod, sechdrs, licenseindex); + /* Fix up syms, so that st_value is a pointer to location. */ err = simplify_symbols(sechdrs, symindex, strindex, mod); if (err < 0) goto cleanup; - /* Set up EXPORTed symbols */ - if (exportindex) { - mod->symbols.num_syms = (sechdrs[exportindex].sh_size - / sizeof(*mod->symbols.syms)); - mod->symbols.syms = (void *)sechdrs[exportindex].sh_addr; - } + /* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */ + mod->symbols.num_syms = (sechdrs[exportindex].sh_size + / sizeof(*mod->symbols.syms)); + mod->symbols.syms = (void *)sechdrs[exportindex].sh_addr; + mod->gpl_symbols.num_syms = (sechdrs[gplindex].sh_size + / sizeof(*mod->symbols.syms)); + mod->gpl_symbols.syms = (void *)sechdrs[gplindex].sh_addr; /* Set up exception table */ if (exindex) { @@ -1228,8 +1289,9 @@ sys_init_module(void *umod, spin_lock_irq(&modlist_lock); list_add(&mod->extable.list, &extables); list_add_tail(&mod->symbols.list, &symbols); - spin_unlock_irq(&modlist_lock); + list_add_tail(&mod->gpl_symbols.list, &symbols); list_add(&mod->list, &modules); + spin_unlock_irq(&modlist_lock); /* Drop lock so they can recurse */ up(&module_mutex); @@ -1256,28 +1318,17 @@ sys_init_module(void *umod, mod->state = MODULE_STATE_LIVE; module_free(mod, mod->module_init); mod->module_init = NULL; + mod->init_size = 0; return 0; } -#ifdef CONFIG_KALLSYMS -static inline int inside_init(struct module *mod, unsigned long addr) +static inline int within(unsigned long addr, void *start, unsigned long size) { - if (mod->module_init - && (unsigned long)mod->module_init <= addr - && (unsigned long)mod->module_init + mod->init_size > addr) - return 1; - return 0; -} - -static inline int inside_core(struct module *mod, unsigned long addr) -{ - if ((unsigned long)mod->module_core <= addr - && (unsigned long)mod->module_core + mod->core_size > addr) - return 1; - return 0; + return ((void *)addr >= start && (void *)addr < start + size); } +#ifdef CONFIG_KALLSYMS static const char *get_ksymbol(struct module *mod, unsigned long addr, unsigned long *size, @@ -1287,7 +1338,7 @@ static const char *get_ksymbol(struct module *mod, unsigned long nextval; /* At worse, next value is at end of module */ - if (inside_core(mod, addr)) + if (within(addr, mod->module_init, mod->init_size)) nextval = (unsigned long)mod->module_core+mod->core_size; else nextval = (unsigned long)mod->module_init+mod->init_size; @@ -1325,7 +1376,8 @@ const char *module_address_lookup(unsigned long addr, struct module *mod; list_for_each_entry(mod, &modules, list) { - if (inside_core(mod, addr) || inside_init(mod, addr)) { + if (within(addr, mod->module_init, mod->init_size) + || within(addr, mod->module_core, mod->core_size)) { *modname = mod->name; return get_ksymbol(mod, addr, size, offset); } @@ -1370,8 +1422,15 @@ static int m_show(struct seq_file *m, void *p) seq_printf(m, "%s %lu", mod->name, mod->init_size + mod->core_size); print_unload_info(m, mod); + seq_printf(m, "\n"); return 0; } + +/* Format: modulename size refcount deps + + Where refcount is a number or -, and deps is a comma-separated list + of depends or -. +*/ struct seq_operations modules_op = { .start = m_start, .next = m_next, @@ -1379,6 +1438,67 @@ struct seq_operations modules_op = { .show = m_show }; +/* Given an address, look for it in the module exception tables. */ +const struct exception_table_entry *search_module_extables(unsigned long addr) +{ + unsigned long flags; + const struct exception_table_entry *e = NULL; + struct exception_table *i; + + spin_lock_irqsave(&modlist_lock, flags); + list_for_each_entry(i, &extables, list) { + if (i->num_entries == 0) + continue; + + e = search_extable(i->entry, i->entry+i->num_entries-1, addr); + if (e) + break; + } + spin_unlock_irqrestore(&modlist_lock, flags); + + /* Now, if we found one, we are running inside it now, hence + we cannot unload the module, hence no refcnt needed. */ + return e; +} + +/* Is this a valid kernel address? We don't grab the lock: we are oopsing. */ +int module_text_address(unsigned long addr) +{ + struct module *mod; + + list_for_each_entry(mod, &modules, list) + if (within(addr, mod->module_init, mod->init_size) + || within(addr, mod->module_core, mod->core_size)) + return 1; + return 0; +} + +/* Provided by the linker */ +extern const struct kernel_symbol __start___ksymtab[]; +extern const struct kernel_symbol __stop___ksymtab[]; +extern const struct kernel_symbol __start___gpl_ksymtab[]; +extern const struct kernel_symbol __stop___gpl_ksymtab[]; + +static struct kernel_symbol_group kernel_symbols, kernel_gpl_symbols; + +static int __init symbols_init(void) +{ + /* Add kernel symbols to symbol table */ + kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab); + kernel_symbols.syms = __start___ksymtab; + kernel_symbols.gplonly = 0; + list_add(&kernel_symbols.list, &symbols); + kernel_gpl_symbols.num_syms = (__stop___gpl_ksymtab + - __start___gpl_ksymtab); + kernel_gpl_symbols.syms = __start___gpl_ksymtab; + kernel_gpl_symbols.gplonly = 1; + list_add(&kernel_gpl_symbols.list, &symbols); + + return 0; +} + +__initcall(symbols_init); + /* Obsolete lvalue for broken code which asks about usage */ int module_dummy_usage = 1; EXPORT_SYMBOL(module_dummy_usage); diff --git a/kernel/panic.c b/kernel/panic.c index 7be1f98be629..4f4e36663617 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -103,7 +103,7 @@ NORET_TYPE void panic(const char * fmt, ...) /** * print_tainted - return a string to represent the kernel taint state. * - * 'P' - Proprietory module has been loaded. + * 'P' - Proprietary module has been loaded. * 'F' - Module has been forcibly loaded. * 'S' - SMP with CPUs not designed for SMP. * @@ -115,7 +115,7 @@ const char *print_tainted() static char buf[20]; if (tainted) { snprintf(buf, sizeof(buf), "Tainted: %c%c%c", - tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', + tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', tainted & TAINT_FORCED_MODULE ? 'F' : ' ', tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); } diff --git a/kernel/pid.c b/kernel/pid.c index ed6adbba677b..f5afb3137e74 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -23,10 +23,11 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/hash.h> -#define PIDHASH_SIZE 4096 -#define pid_hashfn(nr) ((nr >> 8) ^ nr) & (PIDHASH_SIZE - 1) -static struct list_head pid_hash[PIDTYPE_MAX][PIDHASH_SIZE]; +#define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) +static struct list_head *pid_hash[PIDTYPE_MAX]; +static int pidhash_shift; int pid_max = PID_MAX_DEFAULT; int last_pid; @@ -258,20 +259,46 @@ void switch_exec_pids(task_t *leader, task_t *thread) attach_pid(leader, PIDTYPE_SID, leader->session); } +/* + * The pid hash table is scaled according to the amount of memory in the + * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or + * more. + */ void __init pidhash_init(void) { - int i, j; + int i, j, pidhash_size; + unsigned long megabytes = max_pfn >> (20 - PAGE_SHIFT); + + pidhash_shift = max(4, fls(megabytes * 4)); + pidhash_shift = min(12, pidhash_shift); + pidhash_size = 1 << pidhash_shift; + + printk("PID hash table entries: %d (order %d: %Zd bytes)\n", + pidhash_size, pidhash_shift, + pidhash_size * sizeof(struct list_head)); + + for (i = 0; i < PIDTYPE_MAX; i++) { + pid_hash[i] = alloc_bootmem(pidhash_size * + sizeof(struct list_head)); + if (!pid_hash[i]) + panic("Could not alloc pidhash!\n"); + for (j = 0; j < pidhash_size; j++) + INIT_LIST_HEAD(&pid_hash[i][j]); + } +} + +void __init pidmap_init(void) +{ + int i; - /* - * Allocate PID 0, and hash it via all PID types: - */ pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); set_bit(0, pidmap_array->page); atomic_dec(&pidmap_array->nr_free); - for (i = 0; i < PIDTYPE_MAX; i++) { - for (j = 0; j < PIDHASH_SIZE; j++) - INIT_LIST_HEAD(&pid_hash[i][j]); + /* + * Allocate PID 0, and hash it via all PID types: + */ + + for (i = 0; i < PIDTYPE_MAX; i++) attach_pid(current, i, 0); - } } diff --git a/kernel/printk.c b/kernel/printk.c index ffe724fabc0e..9a599c57bf9b 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -31,16 +31,7 @@ #include <asm/uaccess.h> -#if defined(CONFIG_X86_NUMAQ) || defined(CONFIG_IA64) -#define LOG_BUF_LEN (65536) -#elif defined(CONFIG_ARCH_S390) -#define LOG_BUF_LEN (131072) -#elif defined(CONFIG_SMP) -#define LOG_BUF_LEN (32768) -#else -#define LOG_BUF_LEN (16384) /* This must be a power of two */ -#endif - +#define LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) #define LOG_BUF_MASK (LOG_BUF_LEN-1) /* printk's without a loglevel use this.. */ diff --git a/kernel/sched.c b/kernel/sched.c index 11678e2b7f09..152d8f7bad9a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -986,9 +986,7 @@ asmlinkage void schedule(void) } } -#if CONFIG_DEBUG_HIGHMEM check_highmem_ptes(); -#endif need_resched: preempt_disable(); prev = current; diff --git a/lib/crc32.c b/lib/crc32.c index b3defb2db345..01db3a187bc1 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -92,7 +92,7 @@ u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len) crc = __cpu_to_le32(crc); /* Align it */ - for ( ; ((u32)b)&3 && len ; len--){ + for ( ; ((long)b)&3 && len ; len--){ # ifdef __LITTLE_ENDIAN crc = (crc>>8) ^ crc32table_le[ (crc ^ *((u8 *)b)++) & 0xff ]; # else @@ -201,7 +201,7 @@ u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len) crc = __cpu_to_be32(crc); /* Align it */ - for ( ; ((u32)b)&3 && len ; len--){ + for ( ; ((long)b)&3 && len ; len--){ # ifdef __LITTLE_ENDIAN crc = (crc>>8) ^ crc32table_be[ (crc ^ *((u8 *)b)++) & 0xff ]; # else diff --git a/lib/radix-tree.c b/lib/radix-tree.c index c13196a91c7a..dc20f8513946 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -20,10 +20,11 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/mempool.h> #include <linux/module.h> #include <linux/radix-tree.h> +#include <linux/percpu.h> #include <linux/slab.h> +#include <linux/gfp.h> #include <linux/string.h> /* @@ -49,18 +50,74 @@ struct radix_tree_path { * Radix tree node cache. */ static kmem_cache_t *radix_tree_node_cachep; -static mempool_t *radix_tree_node_pool; -static inline struct radix_tree_node * +/* + * Per-cpu pool of preloaded nodes + */ +struct radix_tree_preload { + int nr; + struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH]; +}; +DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; + +/* + * This assumes that the caller has performed appropriate preallocation, and + * that the caller has pinned this thread of control to the current CPU. + */ +static struct radix_tree_node * radix_tree_node_alloc(struct radix_tree_root *root) { - return mempool_alloc(radix_tree_node_pool, root->gfp_mask); + struct radix_tree_node *ret; + + ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask); + if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) { + struct radix_tree_preload *rtp; + + rtp = &__get_cpu_var(radix_tree_preloads); + if (rtp->nr) { + ret = rtp->nodes[rtp->nr - 1]; + rtp->nodes[rtp->nr - 1] = NULL; + rtp->nr--; + } + } + return ret; } static inline void radix_tree_node_free(struct radix_tree_node *node) { - mempool_free(node, radix_tree_node_pool); + kmem_cache_free(radix_tree_node_cachep, node); +} + +/* + * Load up this CPU's radix_tree_node buffer with sufficient objects to + * ensure that the addition of a single element in the tree cannot fail. On + * success, return zero, with preemption disabled. On error, return -ENOMEM + * with preemption not disabled. + */ +int radix_tree_preload(int gfp_mask) +{ + struct radix_tree_preload *rtp; + struct radix_tree_node *node; + int ret = -ENOMEM; + + preempt_disable(); + rtp = &__get_cpu_var(radix_tree_preloads); + while (rtp->nr < ARRAY_SIZE(rtp->nodes)) { + preempt_enable(); + node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); + if (node == NULL) + goto out; + preempt_disable(); + rtp = &__get_cpu_var(radix_tree_preloads); + if (rtp->nr < ARRAY_SIZE(rtp->nodes)) + rtp->nodes[rtp->nr++] = node; + else + kmem_cache_free(radix_tree_node_cachep, node); + } + ret = 0; +out: + return ret; } /* @@ -339,26 +396,12 @@ int radix_tree_delete(struct radix_tree_root *root, unsigned long index) } EXPORT_SYMBOL(radix_tree_delete); -static void radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags) +static void +radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags) { memset(node, 0, sizeof(struct radix_tree_node)); } -static void *radix_tree_node_pool_alloc(int gfp_mask, void *data) -{ - return kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); -} - -static void radix_tree_node_pool_free(void *node, void *data) -{ - kmem_cache_free(radix_tree_node_cachep, node); -} - -/* - * FIXME! 512 nodes is 200-300k of memory. This needs to be - * scaled by the amount of available memory, and hopefully - * reduced also. - */ void __init radix_tree_init(void) { radix_tree_node_cachep = kmem_cache_create("radix_tree_node", @@ -366,8 +409,4 @@ void __init radix_tree_init(void) 0, radix_tree_node_ctor, NULL); if (!radix_tree_node_cachep) panic ("Failed to create radix_tree_node cache\n"); - radix_tree_node_pool = mempool_create(512, radix_tree_node_pool_alloc, - radix_tree_node_pool_free, NULL); - if (!radix_tree_node_pool) - panic ("Failed to create radix_tree_node pool\n"); } diff --git a/mm/filemap.c b/mm/filemap.c index 35137c389b42..18fddd3026f1 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -202,28 +202,31 @@ restart: * * This function does not add the page to the LRU. The caller must do that. */ -int add_to_page_cache(struct page *page, - struct address_space *mapping, pgoff_t offset) +int add_to_page_cache(struct page *page, struct address_space *mapping, + pgoff_t offset, int gfp_mask) { - int error; + int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); - page_cache_get(page); - write_lock(&mapping->page_lock); - error = radix_tree_insert(&mapping->page_tree, offset, page); - if (!error) { - SetPageLocked(page); - ___add_to_page_cache(page, mapping, offset); - } else { - page_cache_release(page); + if (error == 0) { + page_cache_get(page); + write_lock(&mapping->page_lock); + error = radix_tree_insert(&mapping->page_tree, offset, page); + if (!error) { + SetPageLocked(page); + ___add_to_page_cache(page, mapping, offset); + } else { + page_cache_release(page); + } + write_unlock(&mapping->page_lock); + radix_tree_preload_end(); } - write_unlock(&mapping->page_lock); return error; } -int add_to_page_cache_lru(struct page *page, - struct address_space *mapping, pgoff_t offset) +int add_to_page_cache_lru(struct page *page, struct address_space *mapping, + pgoff_t offset, int gfp_mask) { - int ret = add_to_page_cache(page, mapping, offset); + int ret = add_to_page_cache(page, mapping, offset, gfp_mask); if (ret == 0) lru_cache_add(page); return ret; @@ -432,7 +435,8 @@ repeat: if (!cached_page) return NULL; } - err = add_to_page_cache_lru(cached_page, mapping, index); + err = add_to_page_cache_lru(cached_page, mapping, + index, gfp_mask); if (!err) { page = cached_page; cached_page = NULL; @@ -488,6 +492,7 @@ struct page * grab_cache_page_nowait(struct address_space *mapping, unsigned long index) { struct page *page = find_get_page(mapping, index); + int gfp_mask; if (page) { if (!TestSetPageLocked(page)) @@ -495,8 +500,9 @@ grab_cache_page_nowait(struct address_space *mapping, unsigned long index) page_cache_release(page); return NULL; } - page = alloc_pages(mapping->gfp_mask & ~__GFP_FS, 0); - if (page && add_to_page_cache_lru(page, mapping, index)) { + gfp_mask = mapping->gfp_mask & ~__GFP_FS; + page = alloc_pages(gfp_mask, 0); + if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) { page_cache_release(page); page = NULL; } @@ -648,7 +654,8 @@ no_cached_page: break; } } - error = add_to_page_cache_lru(cached_page, mapping, index); + error = add_to_page_cache_lru(cached_page, mapping, + index, GFP_KERNEL); if (error) { if (error == -EEXIST) goto find_page; @@ -940,7 +947,7 @@ static int page_cache_read(struct file * file, unsigned long offset) if (!page) return -ENOMEM; - error = add_to_page_cache_lru(page, mapping, offset); + error = add_to_page_cache_lru(page, mapping, offset, GFP_KERNEL); if (!error) { error = mapping->a_ops->readpage(file, page); page_cache_release(page); @@ -1327,7 +1334,8 @@ repeat: if (!cached_page) return ERR_PTR(-ENOMEM); } - err = add_to_page_cache_lru(cached_page, mapping, index); + err = add_to_page_cache_lru(cached_page, mapping, + index, GFP_KERNEL); if (err == -EEXIST) goto repeat; if (err < 0) { @@ -1406,7 +1414,8 @@ repeat: if (!*cached_page) return NULL; } - err = add_to_page_cache(*cached_page, mapping, index); + err = add_to_page_cache(*cached_page, mapping, + index, GFP_KERNEL); if (err == -EEXIST) goto repeat; if (err == 0) { diff --git a/mm/fremap.c b/mm/fremap.c index 6954430034f4..a8caa89e312c 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -11,6 +11,7 @@ #include <linux/mman.h> #include <linux/pagemap.h> #include <linux/swapops.h> +#include <linux/rmap-locking.h> #include <asm/mmu_context.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> @@ -52,6 +53,7 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, pte_t *pte, entry; pgd_t *pgd; pmd_t *pmd; + struct pte_chain *pte_chain = NULL; pgd = pgd_offset(mm, addr); spin_lock(&mm->page_table_lock); @@ -60,6 +62,7 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, if (!pmd) goto err_unlock; + pte_chain = pte_chain_alloc(GFP_KERNEL); pte = pte_alloc_map(mm, pmd, addr); if (!pte) goto err_unlock; @@ -73,16 +76,17 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, if (prot & PROT_WRITE) entry = pte_mkwrite(pte_mkdirty(entry)); set_pte(pte, entry); - page_add_rmap(page, pte); + pte_chain = page_add_rmap(page, pte, pte_chain); pte_unmap(pte); flush_tlb_page(vma, addr); spin_unlock(&mm->page_table_lock); - + pte_chain_free(pte_chain); return 0; err_unlock: spin_unlock(&mm->page_table_lock); + pte_chain_free(pte_chain); return err; } diff --git a/mm/memory.c b/mm/memory.c index 309ba607c62f..c98bf54855a5 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -44,6 +44,7 @@ #include <linux/highmem.h> #include <linux/pagemap.h> #include <linux/vcache.h> +#include <linux/rmap-locking.h> #include <asm/pgalloc.h> #include <asm/rmap.h> @@ -209,11 +210,22 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src, pgd_t * src_pgd, * dst_pgd; unsigned long address = vma->vm_start; unsigned long end = vma->vm_end; - unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; + unsigned long cow; + struct pte_chain *pte_chain = NULL; if (is_vm_hugetlb_page(vma)) return copy_hugetlb_page_range(dst, src, vma); + pte_chain = pte_chain_alloc(GFP_ATOMIC); + if (!pte_chain) { + spin_unlock(&dst->page_table_lock); + pte_chain = pte_chain_alloc(GFP_KERNEL); + spin_lock(&dst->page_table_lock); + if (!pte_chain) + goto nomem; + } + + cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; src_pgd = pgd_offset(src, address)-1; dst_pgd = pgd_offset(dst, address)-1; @@ -250,7 +262,8 @@ skip_copy_pmd_range: address = (address + PGDIR_SIZE) & PGDIR_MASK; if (pmd_bad(*src_pmd)) { pmd_ERROR(*src_pmd); pmd_clear(src_pmd); -skip_copy_pte_range: address = (address + PMD_SIZE) & PMD_MASK; +skip_copy_pte_range: + address = (address + PMD_SIZE) & PMD_MASK; if (address >= end) goto out; goto cont_copy_pmd_range; @@ -259,13 +272,13 @@ skip_copy_pte_range: address = (address + PMD_SIZE) & PMD_MASK; dst_pte = pte_alloc_map(dst, dst_pmd, address); if (!dst_pte) goto nomem; - spin_lock(&src->page_table_lock); + spin_lock(&src->page_table_lock); src_pte = pte_offset_map_nested(src_pmd, address); do { pte_t pte = *src_pte; - struct page *ptepage; + struct page *page; unsigned long pfn; - + /* copy_one_pte */ if (pte_none(pte)) @@ -276,30 +289,60 @@ skip_copy_pte_range: address = (address + PMD_SIZE) & PMD_MASK; set_pte(dst_pte, pte); goto cont_copy_pte_range_noset; } - ptepage = pte_page(pte); pfn = pte_pfn(pte); + page = pfn_to_page(pfn); if (!pfn_valid(pfn)) goto cont_copy_pte_range; - ptepage = pfn_to_page(pfn); - if (PageReserved(ptepage)) + if (PageReserved(page)) goto cont_copy_pte_range; - /* If it's a COW mapping, write protect it both in the parent and the child */ + /* + * If it's a COW mapping, write protect it both + * in the parent and the child + */ if (cow) { ptep_set_wrprotect(src_pte); pte = *src_pte; } - /* If it's a shared mapping, mark it clean in the child */ + /* + * If it's a shared mapping, mark it clean in + * the child + */ if (vma->vm_flags & VM_SHARED) pte = pte_mkclean(pte); pte = pte_mkold(pte); - get_page(ptepage); + get_page(page); dst->rss++; -cont_copy_pte_range: set_pte(dst_pte, pte); - page_add_rmap(ptepage, dst_pte); -cont_copy_pte_range_noset: address += PAGE_SIZE; +cont_copy_pte_range: + set_pte(dst_pte, pte); + pte_chain = page_add_rmap(page, dst_pte, + pte_chain); + if (pte_chain) + goto cont_copy_pte_range_noset; + pte_chain = pte_chain_alloc(GFP_ATOMIC); + if (pte_chain) + goto cont_copy_pte_range_noset; + + /* + * pte_chain allocation failed, and we need to + * run page reclaim. + */ + pte_unmap_nested(src_pte); + pte_unmap(dst_pte); + spin_unlock(&src->page_table_lock); + spin_unlock(&dst->page_table_lock); + pte_chain = pte_chain_alloc(GFP_KERNEL); + spin_lock(&dst->page_table_lock); + if (!pte_chain) + goto nomem; + spin_lock(&src->page_table_lock); + dst_pte = pte_offset_map(dst_pmd, address); + src_pte = pte_offset_map_nested(src_pmd, + address); +cont_copy_pte_range_noset: + address += PAGE_SIZE; if (address >= end) { pte_unmap_nested(src_pte); pte_unmap(dst_pte); @@ -312,19 +355,23 @@ cont_copy_pte_range_noset: address += PAGE_SIZE; pte_unmap(dst_pte-1); spin_unlock(&src->page_table_lock); -cont_copy_pmd_range: src_pmd++; +cont_copy_pmd_range: + src_pmd++; dst_pmd++; } while ((unsigned long)src_pmd & PMD_TABLE_MASK); } out_unlock: spin_unlock(&src->page_table_lock); out: + pte_chain_free(pte_chain); return 0; nomem: + pte_chain_free(pte_chain); return -ENOMEM; } -static void zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size) +static void +zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size) { unsigned long offset; pte_t *ptep; @@ -806,6 +853,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, { struct page *old_page, *new_page; unsigned long pfn = pte_pfn(pte); + struct pte_chain *pte_chain = NULL; if (!pfn_valid(pfn)) goto bad_wp_page; @@ -834,6 +882,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, if (!new_page) goto no_mem; copy_cow_page(old_page,new_page,address); + pte_chain = pte_chain_alloc(GFP_KERNEL); /* * Re-check the pte - we dropped the lock @@ -845,7 +894,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ++mm->rss; page_remove_rmap(old_page, page_table); break_cow(vma, new_page, address, page_table); - page_add_rmap(new_page, page_table); + pte_chain = page_add_rmap(new_page, page_table, pte_chain); lru_cache_add_active(new_page); /* Free the old page.. */ @@ -855,6 +904,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, spin_unlock(&mm->page_table_lock); page_cache_release(new_page); page_cache_release(old_page); + pte_chain_free(pte_chain); return VM_FAULT_MINOR; bad_wp_page: @@ -992,6 +1042,7 @@ static int do_swap_page(struct mm_struct * mm, swp_entry_t entry = pte_to_swp_entry(orig_pte); pte_t pte; int ret = VM_FAULT_MINOR; + struct pte_chain *pte_chain = NULL; pte_unmap(page_table); spin_unlock(&mm->page_table_lock); @@ -1021,6 +1072,11 @@ static int do_swap_page(struct mm_struct * mm, } mark_page_accessed(page); + pte_chain = pte_chain_alloc(GFP_KERNEL); + if (!pte_chain) { + ret = -ENOMEM; + goto out; + } lock_page(page); /* @@ -1053,13 +1109,14 @@ static int do_swap_page(struct mm_struct * mm, flush_page_to_ram(page); flush_icache_page(vma, page); set_pte(page_table, pte); - page_add_rmap(page, page_table); + pte_chain = page_add_rmap(page, page_table, pte_chain); /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); pte_unmap(page_table); spin_unlock(&mm->page_table_lock); out: + pte_chain_free(pte_chain); return ret; } @@ -1068,11 +1125,27 @@ out: * spinlock held to protect against concurrent faults in * multithreaded programs. */ -static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, pmd_t *pmd, int write_access, unsigned long addr) +static int +do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, + pte_t *page_table, pmd_t *pmd, int write_access, + unsigned long addr) { pte_t entry; struct page * page = ZERO_PAGE(addr); + struct pte_chain *pte_chain; + int ret; + pte_chain = pte_chain_alloc(GFP_ATOMIC); + if (!pte_chain) { + pte_unmap(page_table); + spin_unlock(&mm->page_table_lock); + pte_chain = pte_chain_alloc(GFP_KERNEL); + if (!pte_chain) + goto no_mem; + spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, addr); + } + /* Read-only mapping of ZERO_PAGE. */ entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); @@ -1094,7 +1167,8 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_unmap(page_table); page_cache_release(page); spin_unlock(&mm->page_table_lock); - return VM_FAULT_MINOR; + ret = VM_FAULT_MINOR; + goto out; } mm->rss++; flush_page_to_ram(page); @@ -1104,16 +1178,21 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, } set_pte(page_table, entry); - page_add_rmap(page, page_table); /* ignores ZERO_PAGE */ + /* ignores ZERO_PAGE */ + pte_chain = page_add_rmap(page, page_table, pte_chain); pte_unmap(page_table); /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, addr, entry); spin_unlock(&mm->page_table_lock); - return VM_FAULT_MINOR; + ret = VM_FAULT_MINOR; + goto out; no_mem: - return VM_FAULT_OOM; + ret = VM_FAULT_OOM; +out: + pte_chain_free(pte_chain); + return ret; } /* @@ -1128,14 +1207,17 @@ no_mem: * This is called with the MM semaphore held and the page table * spinlock held. Exit with the spinlock released. */ -static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, +static int +do_no_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access, pte_t *page_table, pmd_t *pmd) { struct page * new_page; pte_t entry; + struct pte_chain *pte_chain; if (!vma->vm_ops || !vma->vm_ops->nopage) - return do_anonymous_page(mm, vma, page_table, pmd, write_access, address); + return do_anonymous_page(mm, vma, page_table, + pmd, write_access, address); pte_unmap(page_table); spin_unlock(&mm->page_table_lock); @@ -1162,6 +1244,7 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, new_page = page; } + pte_chain = pte_chain_alloc(GFP_KERNEL); spin_lock(&mm->page_table_lock); page_table = pte_offset_map(pmd, address); @@ -1184,19 +1267,21 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, if (write_access) entry = pte_mkwrite(pte_mkdirty(entry)); set_pte(page_table, entry); - page_add_rmap(new_page, page_table); + pte_chain = page_add_rmap(new_page, page_table, pte_chain); pte_unmap(page_table); } else { /* One of our sibling threads was faster, back out. */ pte_unmap(page_table); page_cache_release(new_page); spin_unlock(&mm->page_table_lock); + pte_chain_free(pte_chain); return VM_FAULT_MINOR; } /* no need to invalidate: a not-present page shouldn't be cached */ update_mmu_cache(vma, address, entry); spin_unlock(&mm->page_table_lock); + pte_chain_free(pte_chain); return VM_FAULT_MAJOR; } diff --git a/mm/mempool.c b/mm/mempool.c index bfa262857358..027e93c450a2 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -87,7 +87,13 @@ mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn, } return pool; } +EXPORT_SYMBOL(mempool_create); +/* + * mempool_resize is disabled for now, because it has no callers. Feel free + * to turn it back on if needed. + */ +#if 0 /** * mempool_resize - resize an existing memory pool * @pool: pointer to the memory pool which was allocated via @@ -143,16 +149,21 @@ int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask) if (!element) goto out; spin_lock_irqsave(&pool->lock, flags); - if (pool->curr_nr < pool->min_nr) + if (pool->curr_nr < pool->min_nr) { add_element(pool, element); - else - kfree(element); /* Raced */ + } else { + spin_unlock_irqrestore(&pool->lock, flags); + pool->free(element, pool->pool_data); /* Raced */ + spin_lock_irqsave(&pool->lock, flags); + } } out_unlock: spin_unlock_irqrestore(&pool->lock, flags); out: return 0; } +EXPORT_SYMBOL(mempool_resize); +#endif /** * mempool_destroy - deallocate a memory pool @@ -169,6 +180,7 @@ void mempool_destroy(mempool_t *pool) BUG(); /* There were outstanding elements */ free_pool(pool); } +EXPORT_SYMBOL(mempool_destroy); /** * mempool_alloc - allocate an element from a specific memory pool @@ -230,6 +242,7 @@ repeat_alloc: goto repeat_alloc; } +EXPORT_SYMBOL(mempool_alloc); /** * mempool_free - return an element to the pool. @@ -255,6 +268,7 @@ void mempool_free(void *element, mempool_t *pool) } pool->free(element, pool->pool_data); } +EXPORT_SYMBOL(mempool_free); /* * A commonly used alloc and free fn. @@ -264,17 +278,11 @@ void *mempool_alloc_slab(int gfp_mask, void *pool_data) kmem_cache_t *mem = (kmem_cache_t *) pool_data; return kmem_cache_alloc(mem, gfp_mask); } +EXPORT_SYMBOL(mempool_alloc_slab); void mempool_free_slab(void *element, void *pool_data) { kmem_cache_t *mem = (kmem_cache_t *) pool_data; kmem_cache_free(mem, element); } - -EXPORT_SYMBOL(mempool_create); -EXPORT_SYMBOL(mempool_resize); -EXPORT_SYMBOL(mempool_destroy); -EXPORT_SYMBOL(mempool_alloc); -EXPORT_SYMBOL(mempool_free); -EXPORT_SYMBOL(mempool_alloc_slab); EXPORT_SYMBOL(mempool_free_slab); diff --git a/mm/mremap.c b/mm/mremap.c index f295a0d88c0c..c94c9da3f4b5 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -15,6 +15,7 @@ #include <linux/swap.h> #include <linux/fs.h> #include <linux/highmem.h> +#include <linux/rmap-locking.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> @@ -81,7 +82,9 @@ static inline pte_t *alloc_one_pte_map(struct mm_struct *mm, unsigned long addr) return pte; } -static int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst) +static int +copy_one_pte(struct mm_struct *mm, pte_t *src, pte_t *dst, + struct pte_chain **pte_chainp) { int error = 0; pte_t pte; @@ -101,17 +104,25 @@ static int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst) } set_pte(dst, pte); if (page) - page_add_rmap(page, dst); + *pte_chainp = page_add_rmap(page, dst, *pte_chainp); } return error; } -static int move_one_page(struct vm_area_struct *vma, unsigned long old_addr, unsigned long new_addr) +static int +move_one_page(struct vm_area_struct *vma, unsigned long old_addr, + unsigned long new_addr) { struct mm_struct *mm = vma->vm_mm; int error = 0; pte_t *src, *dst; + struct pte_chain *pte_chain; + pte_chain = pte_chain_alloc(GFP_KERNEL); + if (!pte_chain) { + error = -ENOMEM; + goto out; + } spin_lock(&mm->page_table_lock); src = get_one_pte_map_nested(mm, old_addr); if (src) { @@ -127,12 +138,14 @@ static int move_one_page(struct vm_area_struct *vma, unsigned long old_addr, uns dst = alloc_one_pte_map(mm, new_addr); if (src == NULL) src = get_one_pte_map_nested(mm, old_addr); - error = copy_one_pte(mm, src, dst); + error = copy_one_pte(mm, src, dst, &pte_chain); pte_unmap_nested(src); pte_unmap(dst); } flush_tlb_page(vma, old_addr); spin_unlock(&mm->page_table_lock); + pte_chain_free(pte_chain); +out: return error; } diff --git a/mm/readahead.c b/mm/readahead.c index 460ca8a0d149..00de3dcc2829 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -65,7 +65,7 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages, while (!list_empty(pages)) { page = list_entry(pages->prev, struct page, list); list_del(&page->list); - if (add_to_page_cache(page, mapping, page->index)) { + if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { page_cache_release(page); continue; } @@ -93,7 +93,8 @@ static int read_pages(struct address_space *mapping, struct file *filp, for (page_idx = 0; page_idx < nr_pages; page_idx++) { struct page *page = list_entry(pages->prev, struct page, list); list_del(&page->list); - if (!add_to_page_cache(page, mapping, page->index)) { + if (!add_to_page_cache(page, mapping, + page->index, GFP_KERNEL)) { mapping->a_ops->readpage(filp, page); if (!pagevec_add(&lru_pvec, page)) __pagevec_lru_add(&lru_pvec); diff --git a/mm/rmap.c b/mm/rmap.c index b1fc8c10e3f3..da277624459e 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include <linux/rmap-locking.h> #include <linux/cache.h> +#include <linux/percpu.h> #include <asm/pgalloc.h> #include <asm/rmap.h> @@ -51,7 +52,7 @@ struct pte_chain { pte_addr_t ptes[NRPTE]; } ____cacheline_aligned; -static kmem_cache_t *pte_chain_cache; +kmem_cache_t *pte_chain_cache; /* * pte_chain list management policy: @@ -71,39 +72,6 @@ static kmem_cache_t *pte_chain_cache; */ /** - * pte_chain_alloc - allocate a pte_chain struct - * - * Returns a pointer to a fresh pte_chain structure. Allocates new - * pte_chain structures as required. - * Caller needs to hold the page's pte_chain_lock. - */ -static inline struct pte_chain *pte_chain_alloc(void) -{ - struct pte_chain *ret; - - ret = kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC); -#ifdef DEBUG_RMAP - { - int i; - for (i = 0; i < NRPTE; i++) - BUG_ON(ret->ptes[i]); - BUG_ON(ret->next); - } -#endif - return ret; -} - -/** - * pte_chain_free - free pte_chain structure - * @pte_chain: pte_chain struct to free - */ -static inline void pte_chain_free(struct pte_chain *pte_chain) -{ - pte_chain->next = NULL; - kmem_cache_free(pte_chain_cache, pte_chain); -} - -/** ** VM stuff below this comment **/ @@ -156,7 +124,7 @@ int page_referenced(struct page * page) page->pte.direct = pc->ptes[NRPTE-1]; SetPageDirect(page); pc->ptes[NRPTE-1] = 0; - pte_chain_free(pc); + __pte_chain_free(pc); } } return referenced; @@ -170,10 +138,11 @@ int page_referenced(struct page * page) * Add a new pte reverse mapping to a page. * The caller needs to hold the mm->page_table_lock. */ -void page_add_rmap(struct page * page, pte_t * ptep) +struct pte_chain * +page_add_rmap(struct page *page, pte_t *ptep, struct pte_chain *pte_chain) { pte_addr_t pte_paddr = ptep_to_paddr(ptep); - struct pte_chain *pte_chain; + struct pte_chain *cur_pte_chain; int i; #ifdef DEBUG_RMAP @@ -186,7 +155,7 @@ void page_add_rmap(struct page * page, pte_t * ptep) #endif if (!pfn_valid(page_to_pfn(page)) || PageReserved(page)) - return; + return pte_chain; pte_chain_lock(page); @@ -222,30 +191,28 @@ void page_add_rmap(struct page * page, pte_t * ptep) if (PageDirect(page)) { /* Convert a direct pointer into a pte_chain */ ClearPageDirect(page); - pte_chain = pte_chain_alloc(); pte_chain->ptes[NRPTE-1] = page->pte.direct; pte_chain->ptes[NRPTE-2] = pte_paddr; page->pte.direct = 0; page->pte.chain = pte_chain; + pte_chain = NULL; /* We consumed it */ goto out; } - pte_chain = page->pte.chain; - if (pte_chain->ptes[0]) { /* It's full */ - struct pte_chain *new; - - new = pte_chain_alloc(); - new->next = pte_chain; - page->pte.chain = new; - new->ptes[NRPTE-1] = pte_paddr; + cur_pte_chain = page->pte.chain; + if (cur_pte_chain->ptes[0]) { /* It's full */ + pte_chain->next = cur_pte_chain; + page->pte.chain = pte_chain; + pte_chain->ptes[NRPTE-1] = pte_paddr; + pte_chain = NULL; /* We consumed it */ goto out; } - BUG_ON(!pte_chain->ptes[NRPTE-1]); + BUG_ON(!cur_pte_chain->ptes[NRPTE-1]); for (i = NRPTE-2; i >= 0; i--) { - if (!pte_chain->ptes[i]) { - pte_chain->ptes[i] = pte_paddr; + if (!cur_pte_chain->ptes[i]) { + cur_pte_chain->ptes[i] = pte_paddr; goto out; } } @@ -253,7 +220,7 @@ void page_add_rmap(struct page * page, pte_t * ptep) out: pte_chain_unlock(page); inc_page_state(nr_reverse_maps); - return; + return pte_chain; } /** @@ -311,7 +278,7 @@ void page_remove_rmap(struct page * page, pte_t * ptep) if (victim_i == NRPTE-1) { /* Emptied a pte_chain */ page->pte.chain = start->next; - pte_chain_free(start); + __pte_chain_free(start); } else { /* Do singleton->PageDirect here */ } @@ -486,7 +453,7 @@ int try_to_unmap(struct page * page) victim_i++; if (victim_i == NRPTE) { page->pte.chain = start->next; - pte_chain_free(start); + __pte_chain_free(start); start = page->pte.chain; victim_i = 0; } @@ -522,6 +489,58 @@ static void pte_chain_ctor(void *p, kmem_cache_t *cachep, unsigned long flags) memset(pc, 0, sizeof(*pc)); } +DEFINE_PER_CPU(struct pte_chain *, local_pte_chain) = 0; + +/** + * __pte_chain_free - free pte_chain structure + * @pte_chain: pte_chain struct to free + */ +void __pte_chain_free(struct pte_chain *pte_chain) +{ + int cpu = get_cpu(); + struct pte_chain **pte_chainp; + + if (pte_chain->next) + pte_chain->next = NULL; + pte_chainp = &per_cpu(local_pte_chain, cpu); + if (*pte_chainp) + kmem_cache_free(pte_chain_cache, *pte_chainp); + *pte_chainp = pte_chain; + put_cpu(); +} + +/* + * pte_chain_alloc(): allocate a pte_chain structure for use by page_add_rmap(). + * + * The caller of page_add_rmap() must perform the allocation because + * page_add_rmap() is invariably called under spinlock. Often, page_add_rmap() + * will not actually use the pte_chain, because there is space available in one + * of the existing pte_chains which are attached to the page. So the case of + * allocating and then freeing a single pte_chain is specially optimised here, + * with a one-deep per-cpu cache. + */ +struct pte_chain *pte_chain_alloc(int gfp_flags) +{ + int cpu; + struct pte_chain *ret; + struct pte_chain **pte_chainp; + + if (gfp_flags & __GFP_WAIT) + might_sleep(); + + cpu = get_cpu(); + pte_chainp = &per_cpu(local_pte_chain, cpu); + if (*pte_chainp) { + ret = *pte_chainp; + *pte_chainp = NULL; + put_cpu(); + } else { + put_cpu(); + ret = kmem_cache_alloc(pte_chain_cache, gfp_flags); + } + return ret; +} + void __init pte_chain_init(void) { pte_chain_cache = kmem_cache_create( "pte_chain", diff --git a/mm/shmem.c b/mm/shmem.c index d283ef97b644..2bb1a4e0ab18 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -889,7 +889,7 @@ repeat: } if (error || swap.val || (error = add_to_page_cache_lru( - filepage, mapping, idx))) { + filepage, mapping, idx, GFP_ATOMIC))) { spin_unlock(&info->lock); page_cache_release(filepage); shmem_free_block(inode); diff --git a/mm/slab.c b/mm/slab.c index c0fed9f01b4c..c6740a88a703 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -335,8 +335,8 @@ struct kmem_cache_s { /* Magic nums for obj red zoning. * Placed in the first word before and the first word after an obj. */ -#define RED_MAGIC1 0x5A2CF071UL /* when obj is active */ -#define RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */ +#define RED_INACTIVE 0x5A2CF071UL /* when obj is inactive */ +#define RED_ACTIVE 0x170FC2A5UL /* when obj is active */ /* ...and for poisoning */ #define POISON_BEFORE 0x5a /* for use-uninitialised poisoning */ @@ -498,6 +498,19 @@ static void cache_estimate (unsigned long gfporder, size_t size, *left_over = wastage; } +#if DEBUG + +#define slab_error(cachep, msg) __slab_error(__FUNCTION__, cachep, msg) + +static void __slab_error(char *function, kmem_cache_t *cachep, char *msg) +{ + printk(KERN_ERR "slab error in %s(): cache `%s': %s\n", + function, cachep->name, msg); + dump_stack(); +} + +#endif + /* * Start the reap timer running on the target CPU. We run at around 1 to 2Hz. * Add the CPU number into the expiry time to minimize the possibility of the @@ -780,16 +793,19 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) #if DEBUG int i; for (i = 0; i < cachep->num; i++) { - void* objp = slabp->s_mem+cachep->objsize*i; + void *objp = slabp->s_mem + cachep->objsize * i; + if (cachep->flags & SLAB_POISON) check_poison_obj(cachep, objp); if (cachep->flags & SLAB_RED_ZONE) { - if (*((unsigned long*)(objp)) != RED_MAGIC1) - BUG(); + if (*((unsigned long*)(objp)) != RED_INACTIVE) + slab_error(cachep, "start of a freed object " + "was overwritten"); if (*((unsigned long*)(objp + cachep->objsize - - BYTES_PER_WORD)) != RED_MAGIC1) - BUG(); + BYTES_PER_WORD)) != RED_INACTIVE) + slab_error(cachep, "end of a freed object " + "was overwritten"); objp += BYTES_PER_WORD; } if (cachep->dtor && !(cachep->flags & SLAB_POISON)) @@ -1270,9 +1286,9 @@ static void cache_init_objs (kmem_cache_t * cachep, poison_obj(cachep, objp, POISON_BEFORE); if (cachep->flags & SLAB_RED_ZONE) { - *((unsigned long*)(objp)) = RED_MAGIC1; + *((unsigned long*)(objp)) = RED_INACTIVE; *((unsigned long*)(objp + cachep->objsize - - BYTES_PER_WORD)) = RED_MAGIC1; + BYTES_PER_WORD)) = RED_INACTIVE; objp += BYTES_PER_WORD; } /* @@ -1285,11 +1301,13 @@ static void cache_init_objs (kmem_cache_t * cachep, if (cachep->flags & SLAB_RED_ZONE) { objp -= BYTES_PER_WORD; - if (*((unsigned long*)(objp)) != RED_MAGIC1) - BUG(); + if (*((unsigned long*)(objp)) != RED_INACTIVE) + slab_error(cachep, "constructor overwrote the" + " start of an object"); if (*((unsigned long*)(objp + cachep->objsize - - BYTES_PER_WORD)) != RED_MAGIC1) - BUG(); + BYTES_PER_WORD)) != RED_INACTIVE) + slab_error(cachep, "constructor overwrote the" + " end of an object"); } #else if (cachep->ctor) @@ -1444,13 +1462,13 @@ static inline void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp) if (cachep->flags & SLAB_RED_ZONE) { objp -= BYTES_PER_WORD; - if (xchg((unsigned long *)objp, RED_MAGIC1) != RED_MAGIC2) - /* Either write before start, or a double free. */ - BUG(); + if (xchg((unsigned long *)objp, RED_INACTIVE) != RED_ACTIVE) + slab_error(cachep, "double free, or memory before" + " object was overwritten"); if (xchg((unsigned long *)(objp+cachep->objsize - - BYTES_PER_WORD), RED_MAGIC1) != RED_MAGIC2) - /* Either write past end, or a double free. */ - BUG(); + BYTES_PER_WORD), RED_INACTIVE) != RED_ACTIVE) + slab_error(cachep, "double free, or memory after " + " object was overwritten"); } objnr = (objp-slabp->s_mem)/cachep->objsize; @@ -1614,12 +1632,13 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, BUG(); if (cachep->flags & SLAB_RED_ZONE) { /* Set alloc red-zone, and check old one. */ - if (xchg((unsigned long *)objp, RED_MAGIC2) != - RED_MAGIC1) - BUG(); + if (xchg((unsigned long *)objp, RED_ACTIVE) != RED_INACTIVE) + slab_error(cachep, "memory before object was " + "overwritten"); if (xchg((unsigned long *)(objp+cachep->objsize - - BYTES_PER_WORD), RED_MAGIC2) != RED_MAGIC1) - BUG(); + BYTES_PER_WORD), RED_ACTIVE) != RED_INACTIVE) + slab_error(cachep, "memory after object was " + "overwritten"); objp += BYTES_PER_WORD; } if (cachep->ctor && cachep->flags & SLAB_POISON) { diff --git a/mm/swap_state.c b/mm/swap_state.c index 47269578b689..97f2c21c449c 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -78,7 +78,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry) INC_CACHE_INFO(noent_race); return -ENOENT; } - error = add_to_page_cache(page, &swapper_space, entry.val); + error = add_to_page_cache(page, &swapper_space, entry.val, GFP_ATOMIC); /* * Anon pages are already on the LRU, we don't run lru_cache_add here. */ @@ -149,7 +149,8 @@ int add_to_swap(struct page * page) /* * Add it to the swap cache and mark it dirty */ - err = add_to_page_cache(page, &swapper_space, entry.val); + err = add_to_page_cache(page, &swapper_space, + entry.val, GFP_ATOMIC); if (pf_flags & PF_MEMALLOC) current->flags |= PF_MEMALLOC; diff --git a/mm/swapfile.c b/mm/swapfile.c index 067c3095225a..8ce8a1ab91dc 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -20,6 +20,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> +#include <linux/rmap-locking.h> #include <asm/pgtable.h> #include <linux/swapops.h> @@ -377,8 +378,9 @@ void free_swap_and_cache(swp_entry_t entry) * what to do if a write is requested later. */ /* mmlist_lock and vma->vm_mm->page_table_lock are held */ -static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address, - pte_t *dir, swp_entry_t entry, struct page* page) +static void +unuse_pte(struct vm_area_struct *vma, unsigned long address, pte_t *dir, + swp_entry_t entry, struct page *page, struct pte_chain **pte_chainp) { pte_t pte = *dir; @@ -388,7 +390,7 @@ static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address, return; get_page(page); set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); - page_add_rmap(page, dir); + *pte_chainp = page_add_rmap(page, dir, *pte_chainp); swap_free(entry); ++vma->vm_mm->rss; } @@ -400,6 +402,7 @@ static void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, { pte_t * pte; unsigned long end; + struct pte_chain *pte_chain = NULL; if (pmd_none(*dir)) return; @@ -415,11 +418,18 @@ static void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, if (end > PMD_SIZE) end = PMD_SIZE; do { - unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page); + /* + * FIXME: handle pte_chain_alloc() failures + */ + if (pte_chain == NULL) + pte_chain = pte_chain_alloc(GFP_ATOMIC); + unuse_pte(vma, offset+address-vma->vm_start, + pte, entry, page, &pte_chain); address += PAGE_SIZE; pte++; } while (address && (address < end)); pte_unmap(pte - 1); + pte_chain_free(pte_chain); } /* mmlist_lock and vma->vm_mm->page_table_lock are held */ diff --git a/net/core/dv.c b/net/core/dv.c index 6b152aa1cf98..d2b2920312d1 100644 --- a/net/core/dv.c +++ b/net/core/dv.c @@ -97,7 +97,7 @@ void free_divert_blk(struct net_device *dev) /* * Adds a tcp/udp (source or dest) port to an array */ -int add_port(u16 ports[], u16 port) +static int add_port(u16 ports[], u16 port) { int i; @@ -127,7 +127,7 @@ int add_port(u16 ports[], u16 port) /* * Removes a port from an array tcp/udp (source or dest) */ -int remove_port(u16 ports[], u16 port) +static int remove_port(u16 ports[], u16 port) { int i; @@ -150,7 +150,7 @@ int remove_port(u16 ports[], u16 port) } /* Some basic sanity checks on the arguments passed to divert_ioctl() */ -int check_args(struct divert_cf *div_cf, struct net_device **dev) +static int check_args(struct divert_cf *div_cf, struct net_device **dev) { char devname[32]; int ret; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d1d7cf33713a..9ca1db5863ad 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -234,7 +234,7 @@ static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r) { struct rt_cache_iter_state *st = seq->private; - read_barrier_depends(); + smp_read_barrier_depends(); r = r->u.rt_next; while (!r) { rcu_read_unlock(); @@ -718,7 +718,18 @@ restart: if (compare_keys(&rth->fl, &rt->fl)) { /* Put it first */ *rthp = rth->u.rt_next; + /* + * Since lookup is lockfree, the deletion + * must be visible to another weakly ordered CPU before + * the insertion at the start of the hash chain. + */ + smp_wmb(); rth->u.rt_next = rt_hash_table[hash].chain; + /* + * Since lookup is lockfree, the update writes + * must be ordered for consistency on SMP. + */ + smp_wmb(); rt_hash_table[hash].chain = rth; rth->u.dst.__use++; @@ -900,7 +911,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw, while ((rth = *rthp) != NULL) { struct rtable *rt; - read_barrier_depends(); + smp_read_barrier_depends(); if (rth->fl.fl4_dst != daddr || rth->fl.fl4_src != skeys[i] || rth->fl.fl4_tos != tos || @@ -1148,7 +1159,7 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu) rcu_read_lock(); for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { - read_barrier_depends(); + smp_read_barrier_depends(); if (rth->fl.fl4_dst == daddr && rth->fl.fl4_src == skeys[i] && rth->rt_dst == daddr && @@ -1740,7 +1751,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, rcu_read_lock(); for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { - read_barrier_depends(); + smp_read_barrier_depends(); if (rth->fl.fl4_dst == daddr && rth->fl.fl4_src == saddr && rth->fl.iif == iif && @@ -2105,7 +2116,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) rcu_read_lock(); for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { - read_barrier_depends(); + smp_read_barrier_depends(); if (rth->fl.fl4_dst == flp->fl4_dst && rth->fl.fl4_src == flp->fl4_src && rth->fl.iif == 0 && @@ -2335,7 +2346,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); for (rt = rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) { - read_barrier_depends(); + smp_read_barrier_depends(); if (idx < s_idx) continue; skb->dst = dst_clone(&rt->u.dst); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index d405be5dc1ce..2b20154fe0f5 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -402,7 +402,13 @@ static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff) if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8)) goto fail; - len = (skb->h.raw[1]+1)<<2; + /* + * RFC2402 2.2 Payload Length + * The 8-bit field specifies the length of AH in 32-bit words + * (4-byte units), minus "2". + * -- Noriaki Takamiya @USAGI Project + */ + len = (skb->h.raw[1]+2)<<2; if (len&7) goto fail; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 546d38101aa8..9494ca19aa54 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -22,6 +22,7 @@ #include <linux/ctype.h> #include <asm/uaccess.h> #include <linux/poll.h> +#include <linux/seq_file.h> #include <linux/proc_fs.h> #include <linux/net.h> #include <asm/ioctls.h> @@ -160,7 +161,9 @@ static spinlock_t cache_list_lock = SPIN_LOCK_UNLOCKED; static struct cache_detail *current_detail; static int current_index; -struct file_operations cache_file_operations; +static struct file_operations cache_file_operations; +static struct file_operations content_file_operations; +static struct file_operations cache_flush_operations; void cache_register(struct cache_detail *cd) { @@ -169,13 +172,32 @@ void cache_register(struct cache_detail *cd) struct proc_dir_entry *p; cd->proc_ent->owner = THIS_MODULE; - p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent); - if (p) { - p->proc_fops = &cache_file_operations; - p->owner = THIS_MODULE; - p->data = cd; + p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, + cd->proc_ent); + if (p) { + p->proc_fops = &cache_flush_operations; + p->owner = THIS_MODULE; + p->data = cd; + } + + if (cd->cache_request || cd->cache_parse) { + p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR, + cd->proc_ent); + if (p) { + p->proc_fops = &cache_file_operations; + p->owner = THIS_MODULE; + p->data = cd; + } } + if (cd->cache_show) { + p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR, + cd->proc_ent); + if (p) { + p->proc_fops = &content_file_operations; + p->owner = THIS_MODULE; + p->data = cd; + } + } } rwlock_init(&cd->hash_lock); INIT_LIST_HEAD(&cd->queue); @@ -183,7 +205,7 @@ void cache_register(struct cache_detail *cd) cd->nextcheck = 0; cd->entries = 0; atomic_set(&cd->readers, 0); - cd->last_close = get_seconds(); + cd->last_close = 0; list_add(&cd->others, &cache_list); spin_unlock(&cache_list_lock); } @@ -710,7 +732,7 @@ cache_release(struct inode *inode, struct file *filp) -struct file_operations cache_file_operations = { +static struct file_operations cache_file_operations = { .llseek = no_llseek, .read = cache_read, .write = cache_write, @@ -799,8 +821,8 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen) len -= 2; while (blen && len >= 2) { unsigned char c = *buf++; - *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'0'); - *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'0'); + *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); + *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); len -= 2; blen--; } @@ -902,7 +924,7 @@ int qword_get(char **bpp, char *dest, int bufsize) } } else { /* text with \nnn octal quoting */ - while (*bp != ' ' && *bp && len < bufsize-1) { + while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) { if (*bp == '\\' && isodigit(bp[1]) && (bp[1] <= '3') && isodigit(bp[2]) && @@ -918,11 +940,205 @@ int qword_get(char **bpp, char *dest, int bufsize) len++; } } - *dest = '\0'; } + if (*bp != ' ' && *bp != '\n' && *bp != '\0') + return -1; + while (*bp == ' ') bp++; *bpp = bp; - if (*bp == ' ' || *bp == '\n' || *bp == '\0') - return len; - return -1; + *dest = '\0'; + return len; } + + +/* + * support /proc/sunrpc/cache/$CACHENAME/content + * as a seqfile. + * We call ->cache_show passing NULL for the item to + * get a header, then pass each real item in the cache + */ + +struct handle { + struct cache_detail *cd; + char *pbuf; +}; + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + loff_t n = *pos; + unsigned hash, entry; + struct cache_head *ch; + struct cache_detail *cd = ((struct handle*)m->private)->cd; + + + read_lock(&cd->hash_lock); + if (!n--) + return (void *)1; + hash = n >> 32; + entry = n & ((1LL<<32) - 1); + + for (ch=cd->hash_table[hash]; ch; ch=ch->next) + if (!entry--) + return ch; + n &= ~((1LL<<32) - 1); + do { + hash++; + n += 1LL<<32; + } while(hash < cd->hash_size && + cd->hash_table[hash]==NULL); + if (hash >= cd->hash_size) + return NULL; + *pos = n+1; + return cd->hash_table[hash]; +} + +static void *c_next(struct seq_file *m, void *p, loff_t *pos) +{ + struct cache_head *ch = p; + int hash = (*pos >> 32); + struct cache_detail *cd = ((struct handle*)m->private)->cd; + + if (p == (void *)1) + hash = 0; + else if (ch->next == NULL) { + hash++; + *pos += 1LL<<32; + } else { + ++*pos; + return ch->next; + } + *pos &= ~((1LL<<32) - 1); + while (hash < cd->hash_size && + cd->hash_table[hash] == NULL) { + hash++; + *pos += 1LL<<32; + } + if (hash >= cd->hash_size) + return NULL; + ++*pos; + return cd->hash_table[hash]; +} + +static void c_stop(struct seq_file *m, void *p) +{ + struct cache_detail *cd = ((struct handle*)m->private)->cd; + read_unlock(&cd->hash_lock); +} + +static int c_show(struct seq_file *m, void *p) +{ + struct cache_head *cp = p; + struct cache_detail *cd = ((struct handle*)m->private)->cd; + char *pbuf = ((struct handle*)m->private)->pbuf; + + if (p == (void *)1) + return cd->cache_show(m, cd, NULL, pbuf); + + cache_get(cp); + if (cache_check(cd, cp, NULL)) + return 0; + cache_put(cp, cd); + + return cd->cache_show(m, cd, cp, pbuf); +} + +struct seq_operations cache_content_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show, +}; + +static int content_open(struct inode *inode, struct file *file) +{ + int res; + char *namebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); + struct handle *han; + struct cache_detail *cd = PDE(inode)->data; + + if (namebuf == NULL) + return -ENOMEM; + + han = kmalloc(sizeof(*han), GFP_KERNEL); + if (han == NULL) { + kfree(namebuf); + return -ENOMEM; + } + han->pbuf = namebuf; + han->cd = cd; + + res = seq_open(file, &cache_content_op); + if (res) { + kfree(namebuf); + kfree(han); + } else + ((struct seq_file *)file->private_data)->private = han; + + return res; +} +static int content_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + struct handle *han = m->private; + kfree(han->pbuf); + kfree(han); + m->private = NULL; + return seq_release(inode, file); +} + +static struct file_operations content_file_operations = { + .open = content_open, + .read = seq_read, + .llseek = seq_lseek, + .release = content_release, +}; + +static ssize_t read_flush(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data; + char tbuf[20]; + unsigned long p = *ppos; + int len; + + sprintf(tbuf, "%lu\n", cd->flush_time); + len = strlen(tbuf); + if (p >= len) + return 0; + len -= p; + if (len > count) len = count; + if (copy_to_user(buf, (void*)(tbuf+p), len)) + len = -EFAULT; + else + *ppos += len; + return len; +} + +static ssize_t write_flush(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data; + char tbuf[20]; + char *ep; + long flushtime; + if (*ppos || count > sizeof(tbuf)-1) + return -EINVAL; + if (copy_from_user(tbuf, buf, count)) + return -EFAULT; + tbuf[count] = 0; + flushtime = simple_strtoul(tbuf, &ep, 0); + if (*ep && *ep != '\n') + return -EINVAL; + + cd->flush_time = flushtime; + cd->nextcheck = get_seconds(); + cache_flush(); + + *ppos += count; + return count; +} + +static struct file_operations cache_flush_operations = { + .read = read_flush, + .write = write_flush, +}; diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 39a46f7a12f5..8f7db60bb89c 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -16,6 +16,7 @@ #include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/svcauth.h> #include <linux/err.h> +#include <linux/hash.h> #define RPCDBG_FACILITY RPCDBG_AUTH @@ -111,14 +112,22 @@ svc_auth_unregister(rpc_authflavor_t flavor) * it will complain. */ -int name_hash(char *name, int size) +int hash_mem(char *buf, int len, int bits) { int hash = 0; - while (*name) { - hash += *name; - name++; + unsigned long l; + while (len >= BITS_PER_LONG/8) { + l = *(unsigned long *)buf; + buf += BITS_PER_LONG/8; + len -= BITS_PER_LONG/8; + hash ^= hash_long(l, bits); } - return hash % size; + if (len) { + l=0; + memcpy((char*)&l, buf, len); + hash ^= hash_long(l, bits); + } + return hash; } @@ -161,7 +170,7 @@ void auth_domain_put(struct auth_domain *dom) static inline int auth_domain_hash(struct auth_domain *item) { - return name_hash(item->name, DN_HASHMAX); + return hash_str(item->name, DN_HASHBITS); } static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item) { diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 37e74850f362..fb54ca13737d 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -5,6 +5,8 @@ #include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/svcauth.h> #include <linux/err.h> +#include <linux/seq_file.h> +#include <linux/hash.h> #define RPCDBG_FACILITY RPCDBG_AUTH @@ -107,7 +109,8 @@ void ip_map_put(struct cache_head *item, struct cache_detail *cd) static inline int ip_map_hash(struct ip_map *item) { - return (name_hash(item->m_class, IP_HASHMAX) ^ item->m_addr.s_addr) & IP_HASHMASK; + return hash_str(item->m_class, IP_HASHBITS) ^ + hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS); } static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp) { @@ -210,6 +213,33 @@ static int ip_map_parse(struct cache_detail *cd, return 0; } +static int ip_map_show(struct seq_file *m, + struct cache_detail *cd, + struct cache_head *h, + char *pbuf) +{ + struct ip_map *im; + struct in_addr addr; + + if (h == NULL) { + seq_puts(m, "#class IP domain\n"); + return 0; + } + im = container_of(h, struct ip_map, h); + /* class addr domain */ + addr = im->m_addr; + seq_printf(m, "%s %d.%d.%d.%d %s\n", + im->m_class, + htonl(addr.s_addr) >> 24 & 0xff, + htonl(addr.s_addr) >> 16 & 0xff, + htonl(addr.s_addr) >> 8 & 0xff, + htonl(addr.s_addr) >> 0 & 0xff, + im->m_client->h.name + ); + return 0; +} + + struct cache_detail ip_map_cache = { .hash_size = IP_HASHMAX, .hash_table = ip_table, @@ -217,6 +247,7 @@ struct cache_detail ip_map_cache = { .cache_put = ip_map_put, .cache_request = ip_map_request, .cache_parse = ip_map_parse, + .cache_show = ip_map_show, }; static DefineSimpleCacheLookup(ip_map) @@ -268,20 +299,17 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr) if (!ipm) return NULL; + if (cache_check(&ip_map_cache, &ipm->h, NULL)) + return NULL; - if (test_bit(CACHE_VALID, &ipm->h.flags) && - (ipm->m_client->addr_changes - ipm->m_add_change) >0) + if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { set_bit(CACHE_NEGATIVE, &ipm->h.flags); - - if (!test_bit(CACHE_VALID, &ipm->h.flags)) - rv = NULL; - else if (test_bit(CACHE_NEGATIVE, &ipm->h.flags)) rv = NULL; - else { + } else { rv = &ipm->m_client->h; cache_get(&rv->h); } - if (ipm) ip_map_put(&ipm->h, &ip_map_cache); + ip_map_put(&ipm->h, &ip_map_cache); return rv; } diff --git a/sound/sound_firmware.c b/sound/sound_firmware.c index 49c122d62d7a..cfd9a322e463 100644 --- a/sound/sound_firmware.c +++ b/sound/sound_firmware.c @@ -7,7 +7,6 @@ #include <linux/unistd.h> #include <asm/uaccess.h> -static int errno; static int do_mod_firmware_load(const char *fn, char **fp) { int fd; |
