diff options
| author | Patrick Mochel <mochel@osdl.org> | 2003-01-01 21:59:24 -0600 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2003-01-01 21:59:24 -0600 |
| commit | 5816344d714eaf45f2305ac2215894e41c4fd297 (patch) | |
| tree | ccd8b9c30cfdfba2a1271e0015ff9932fb284cf0 | |
| parent | 20d7bffcf7a196e0a6a20baebfe3e00c0919253c (diff) | |
| parent | 4c55cc628bf2eaa15a8d5814974ad61e71d7e30c (diff) | |
Merge bk://linux.bkbits.net/linux-2.5
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
95 files changed, 1825 insertions, 1608 deletions
@@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 53 +SUBLEVEL = 54 EXTRAVERSION = # *DOCUMENTATION* diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index a367cc15662d..bb14b26258c5 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -35,6 +35,7 @@ #include <linux/ipc.h> #include <linux/namei.h> #include <linux/uio.h> +#include <linux/vfs.h> #include <asm/fpu.h> #include <asm/io.h> diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 41ab5fc35443..3a2b5aaaa3b6 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -67,18 +67,12 @@ void module_free(struct module *module, void *region) vfree(region); } -long -module_core_size(const Elf32_Ehdr *hdr, const Elf32_Shdr *sechdrs, - const char *secstrings, struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { - return module->core_size; -} - -long -module_init_size(const Elf32_Ehdr *hdr, const Elf32_Shdr *sechdrs, - const char *secstrings, struct module *module) -{ - return module->init_size; + return 0; } int @@ -88,7 +82,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, Elf32_Shdr *symsec = sechdrs + symindex; Elf32_Shdr *relsec = sechdrs + relindex; Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; - Elf32_Rel *rel = (void *)relsec->sh_offset; + Elf32_Rel *rel = (void *)relsec->sh_addr; unsigned int i; for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { @@ -103,7 +97,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, return -ENOEXEC; } - sym = ((Elf32_Sym *)symsec->sh_offset) + offset; + sym = ((Elf32_Sym *)symsec->sh_addr) + offset; if (!sym->st_value) { printk(KERN_WARNING "%s: unknown symbol %s\n", module->name, strtab + sym->st_name); @@ -118,7 +112,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, return -ENOEXEC; } - loc = dstsec->sh_offset + rel->r_offset; + loc = dstsec->sh_addr + rel->r_offset; switch (ELF32_R_TYPE(rel->r_info)) { case R_ARM_ABS32: diff --git a/arch/i386/kernel/module.c b/arch/i386/kernel/module.c index 0ab783d158a2..d71b0e367eb6 100644 --- a/arch/i386/kernel/module.c +++ b/arch/i386/kernel/module.c @@ -45,20 +45,12 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -long module_core_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { - return module->core_size; -} - -long module_init_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } int apply_relocate(Elf32_Shdr *sechdrs, @@ -68,7 +60,7 @@ int apply_relocate(Elf32_Shdr *sechdrs, struct module *me) { unsigned int i; - Elf32_Rel *rel = (void *)sechdrs[relsec].sh_offset; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; uint32_t *location; @@ -76,10 +68,10 @@ int apply_relocate(Elf32_Shdr *sechdrs, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_offset + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(rel[i].r_info); if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index d7ffb0124d77..73ebb59b2b88 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -48,6 +48,7 @@ #include <linux/stat.h> #include <linux/ipc.h> #include <linux/compat.h> +#include <linux/vfs.h> #include <asm/types.h> #include <asm/uaccess.h> diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 72a78d597d57..4c319482e1b8 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -22,6 +22,7 @@ #include <linux/smp_lock.h> #include <linux/utsname.h> #include <linux/file.h> +#include <linux/vfs.h> #include <asm/ptrace.h> #include <asm/page.h> diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c index 5a3a8f4d8c28..33f6bc1d11ac 100644 --- a/arch/mips64/kernel/linux32.c +++ b/arch/mips64/kernel/linux32.c @@ -27,6 +27,7 @@ #include <linux/timex.h> #include <linux/dnotify.h> #include <linux/compat.h> +#include <linux/vfs.h> #include <net/sock.h> #include <asm/uaccess.h> diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c index da0760d5e6a0..f3fbb3202dec 100644 --- a/arch/parisc/hpux/sys_hpux.c +++ b/arch/parisc/hpux/sys_hpux.c @@ -10,6 +10,7 @@ #include <linux/smp_lock.h> #include <linux/utsname.h> #include <linux/vmalloc.h> +#include <linux/vfs.h> #include <asm/errno.h> #include <asm/pgalloc.h> diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index bb31f8376115..adbbc83990c9 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -52,6 +52,7 @@ #include <linux/mman.h> #include <linux/binfmts.h> #include <linux/namei.h> +#include <linux/vfs.h> #include <asm/types.h> #include <asm/uaccess.h> diff --git a/arch/ppc/kernel/module.c b/arch/ppc/kernel/module.c index 90f3228d20b0..8e396b7f40c0 100644 --- a/arch/ppc/kernel/module.c +++ b/arch/ppc/kernel/module.c @@ -101,24 +101,31 @@ static unsigned long get_plt_size(const Elf32_Ehdr *hdr, return ret; } -long module_core_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(Elf32_Ehdr *hdr, + Elf32_Shdr *sechdrs, + const char *secstrings, + struct module *me) { - module->arch.core_plt_offset = ALIGN(module->core_size, 4); - return module->arch.core_plt_offset - + get_plt_size(hdr, sechdrs, secstrings, 0); -} + unsigned int i; -long module_init_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - module->arch.init_plt_offset = ALIGN(module->init_size, 4); - return module->arch.init_plt_offset - + get_plt_size(hdr, sechdrs, secstrings, 1); + /* Find .plt and .pltinit sections */ + for (i = 0; i < hdr->e_shnum; i++) { + if (strcmp(secstrings + sechdrs[i].sh_name, ".plt.init") == 0) + me->arch.init_plt_section = i; + else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0) + me->arch.core_plt_section = i; + } + if (!me->arch.core_plt_section || !me->arch.init_plt_section) { + printk("Module doesn't contain .plt or .plt.init sections.\n"); + return -ENOEXEC; + } + + /* Override their sizes */ + sechdrs[me->arch.core_plt_section].sh_size + = get_plt_size(hdr, sechdrs, secstrings, 0); + sechdrs[me->arch.init_plt_section].sh_size + = get_plt_size(hdr, sechdrs, secstrings, 1); + return 0; } int apply_relocate(Elf32_Shdr *sechdrs, @@ -141,17 +148,20 @@ static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) } /* Set up a trampoline in the PLT to bounce us to the distant function */ -static uint32_t do_plt_call(void *location, Elf32_Addr val, struct module *mod) +static uint32_t do_plt_call(void *location, + Elf32_Addr val, + Elf32_Shdr *sechdrs, + struct module *mod) { struct ppc_plt_entry *entry; DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); /* Init, or core PLT? */ if (location >= mod->module_core - && location < mod->module_core + mod->arch.core_plt_offset) - entry = mod->module_core + mod->arch.core_plt_offset; + && location < mod->module_core + mod->core_size) + entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; else - entry = mod->module_init + mod->arch.init_plt_offset; + entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; /* Find this entry, or if that fails, the next avail. entry */ while (entry->jump[0]) { @@ -176,7 +186,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, struct module *module) { unsigned int i; - Elf32_Rela *rela = (void *)sechdrs[relsec].sh_offset; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; uint32_t *location; uint32_t value; @@ -185,10 +195,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rela[i].r_offset; /* This is the symbol it is referring to */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_offset + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(rela[i].r_info); if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n", @@ -220,7 +230,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, case R_PPC_REL24: if ((int)(value - (uint32_t)location) < -0x02000000 || (int)(value - (uint32_t)location) >= 0x02000000) - value = do_plt_call(location, value, module); + value = do_plt_call(location, value, + sechdrs, module); /* Only replace bits 2 through 26 */ DEBUGP("REL24 value = %08X. location = %08X\n", diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 314160ffb68f..d1d4dd05c212 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -51,26 +51,15 @@ void module_free(struct module *mod, void *module_region) table entries. */ } -/* s390/s390x needs additional memory for GOT/PLT sections. */ -long module_core_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { // FIXME: add space needed for GOT/PLT - return module->core_size; -} - -long module_init_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } - - int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -78,7 +67,7 @@ int apply_relocate(Elf_Shdr *sechdrs, struct module *me) { unsigned int i; - ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_offset; + ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_addr; ElfW(Sym) *sym; ElfW(Addr) *location; @@ -86,10 +75,10 @@ int apply_relocate(Elf_Shdr *sechdrs, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to */ - sym = (ElfW(Sym) *)sechdrs[symindex].sh_offset + sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr + ELFW(R_SYM)(rel[i].r_info); if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c index 46dcd3752a40..ea87f61f1b6f 100644 --- a/arch/s390x/kernel/linux32.c +++ b/arch/s390x/kernel/linux32.c @@ -57,6 +57,7 @@ #include <linux/sysctl.h> #include <linux/binfmts.h> #include <linux/compat.h> +#include <linux/vfs.h> #include <asm/types.h> #include <asm/ipc.h> diff --git a/arch/s390x/kernel/module.c b/arch/s390x/kernel/module.c index 28b0627abc7f..61f3b34e90be 100644 --- a/arch/s390x/kernel/module.c +++ b/arch/s390x/kernel/module.c @@ -52,25 +52,15 @@ void module_free(struct module *mod, void *module_region) } /* s390/s390x needs additional memory for GOT/PLT sections. */ -long module_core_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { // FIXME: add space needed for GOT/PLT - return module->core_size; -} - -long module_init_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } - - int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -78,7 +68,7 @@ int apply_relocate(Elf_Shdr *sechdrs, struct module *me) { unsigned int i; - ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_offset; + ElfW(Rel) *rel = (void *)sechdrs[relsec].sh_addr; ElfW(Sym) *sym; ElfW(Addr) *location; @@ -86,10 +76,10 @@ int apply_relocate(Elf_Shdr *sechdrs, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to */ - sym = (ElfW(Sym) *)sechdrs[symindex].sh_offset + sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr + ELFW(R_SYM)(rel[i].r_info); if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 9837dbec56c2..348c24f63d85 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -37,20 +37,12 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -long module_core_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { - return module->core_size; -} - -long module_init_size(const Elf32_Ehdr *hdr, - const Elf32_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } int apply_relocate(Elf32_Shdr *sechdrs, @@ -71,7 +63,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, struct module *me) { unsigned int i; - Elf32_Rela *rel = (void *)sechdrs[relsec].sh_offset; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; u8 *location; u32 *loc32; @@ -80,11 +72,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, Elf32_Addr v; /* This is where to make the change */ - location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; loc32 = (u32 *) location; /* This is the symbol it is referring to */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_offset + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(rel[i].r_info); if (!(v = sym->st_value)) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c index 4e750c98757c..dc0daa59aac1 100644 --- a/arch/sparc64/kernel/module.c +++ b/arch/sparc64/kernel/module.c @@ -144,20 +144,12 @@ void module_free(struct module *mod, void *module_region) } /* We don't need anything special. */ -long module_core_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { - return module->core_size; -} - -long module_init_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } int apply_relocate(Elf64_Shdr *sechdrs, @@ -178,7 +170,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, struct module *me) { unsigned int i; - Elf64_Rela *rel = (void *)sechdrs[relsec].sh_offset; + Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf64_Sym *sym; u8 *location; u32 *loc32; @@ -187,14 +179,14 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, Elf64_Addr v; /* This is where to make the change */ - location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; loc32 = (u32 *) location; BUG_ON(((u64)location >> (u64)32) != (u64)0); /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_offset + sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + ELF64_R_SYM(rel[i].r_info); if (!(v = sym->st_value)) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 34c40fe2c7c8..2ddea3f674e8 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -52,6 +52,7 @@ #include <linux/dnotify.h> #include <linux/security.h> #include <linux/compat.h> +#include <linux/vfs.h> #include <asm/types.h> #include <asm/ipc.h> diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index e0093cd7abb7..b20061522f93 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -20,6 +20,7 @@ #include <linux/resource.h> #include <linux/quotaops.h> #include <linux/mount.h> +#include <linux/vfs.h> #include <asm/uaccess.h> #include <asm/string.h> diff --git a/arch/v850/kernel/module.c b/arch/v850/kernel/module.c index 5f69de09cc42..437b31f989fb 100644 --- a/arch/v850/kernel/module.c +++ b/arch/v850/kernel/module.c @@ -160,7 +160,7 @@ int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab, struct module *mod) { unsigned int i; - Elf32_Rela *rela = (void *)sechdrs[relsec].sh_offset; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; DEBUGP ("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); @@ -168,11 +168,11 @@ int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab, for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) { /* This is where to make the change */ uint32_t *loc - = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rela[i].r_offset); /* This is the symbol it is referring to */ Elf32_Sym *sym - = ((Elf32_Sym *)sechdrs[symindex].sh_offset + = ((Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM (rela[i].r_info)); uint32_t val = sym->st_value; diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 3d9ef0ff67ce..9a53811f2499 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -58,6 +58,7 @@ #include <linux/init.h> #include <linux/aio_abi.h> #include <linux/compat.h> +#include <linux/vfs.h> #include <asm/mman.h> #include <asm/types.h> #include <asm/uaccess.h> diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c index bd2595bb1b2d..c585076087db 100644 --- a/arch/x86_64/kernel/module.c +++ b/arch/x86_64/kernel/module.c @@ -26,20 +26,12 @@ #define DEBUGP(fmt...) /* We don't need anything special. */ -long module_core_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs, - const char *secstrings, - struct module *module) +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) { - return module->core_size; -} - -long module_init_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs, - const char *secstrings, - struct module *module) -{ - return module->init_size; + return 0; } int apply_relocate_add(Elf64_Shdr *sechdrs, @@ -49,7 +41,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, struct module *me) { unsigned int i; - Elf64_Rela *rel = (void *)sechdrs[relsec].sh_offset; + Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf64_Sym *sym; void *loc; u64 val; @@ -58,11 +50,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_offset + sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + ELF64_R_SYM(rel[i].r_info); if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n", diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index 41f99c9eb818..17a32bc17d96 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -119,9 +119,6 @@ static int __init miropcm20_rds_init(void) return -EINVAL; printk("miropcm20-rds: userinterface driver loaded.\n"); -#if DEBUG - printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0)); -#endif return 0; } diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h index 99575438c027..bb8cb954e3a2 100644 --- a/drivers/message/fusion/linux_compat.h +++ b/drivers/message/fusion/linux_compat.h @@ -246,35 +246,17 @@ static __inline__ int __get_order(unsigned long size) #endif /* - * We use our new error handling code if the kernel version is 2.5.1 or newer. + * We use our new error handling code if the kernel version is 2.4.18 or newer. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) #define MPT_SCSI_USE_NEW_EH #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_lock(iocp, flags) \ - spin_lock_irqsave(&iocp->FreeQlock, flags) -#else -#define mptscsih_lock(iocp, flags) \ -({ save_flags(flags); \ - cli(); \ -}) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_unlock(iocp, flags) \ - spin_unlock_irqrestore(&iocp->FreeQlock, flags) -#else -#define mptscsih_unlock(iocp, flags) restore_flags(flags); -#endif - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) -#define mpt_work_struct work_struct +#define mpt_work_struct work_struct #define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data) #else -#define mpt_work_struct tq_struct +#define mpt_work_struct tq_struct #define MPT_INIT_WORK(_task, _func, _data) \ ({ (_task)->sync = 0; \ (_task)->routine = (_func); \ @@ -282,6 +264,13 @@ static __inline__ int __get_order(unsigned long size) }) #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) +#define mptscsih_sync_irq(_irq) synchronize_irq(_irq) +#else +#define mptscsih_sync_irq(_irq) synchronize_irq() +#endif + + /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index cb7d91bc07a6..16e0b31dc75e 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -49,7 +49,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.c,v 1.123 2002/10/17 20:15:56 pdelaney Exp $ + * $Id: mptbase.c,v 1.125 2002/12/03 21:26:32 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -208,6 +208,7 @@ static int GetIoUnitPage2(MPT_ADAPTER *ioc); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); static int mpt_findImVolumes(MPT_ADAPTER *ioc); +static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); static void mpt_timer_expired(unsigned long data); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); @@ -443,7 +444,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) */ if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) || (mf < ioc->req_frames)) ) { - printk(MYIOC_s_WARN_FMT + printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx); cb_idx = 0; pa = 0; @@ -451,14 +452,14 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) } if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth)) || (mr < ioc->reply_frames)) ) { - printk(MYIOC_s_WARN_FMT + printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr); cb_idx = 0; pa = 0; freeme = 0; } if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) { - printk(MYIOC_s_WARN_FMT + printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx); cb_idx = 0; pa = 0; @@ -576,9 +577,11 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) CONFIGPARMS *pCfg; unsigned long flags; - dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n", + dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n", ioc->name, mf, reply)); + DBG_DUMP_REPLY_FRAME(reply) + pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); if (pCfg) { @@ -599,7 +602,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) u16 status; status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n", + dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n", status, le32_to_cpu(pReply->IOCLogInfo))); pCfg->status = status; @@ -943,7 +946,7 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) * mpt_add_sge - Place a simple SGE at address pAddr. * @pAddr: virtual address for SGE * @flagslength: SGE flags and data transfer length - * @dma_addr: Physical address + * @dma_addr: Physical address * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. @@ -973,7 +976,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) * @pAddr: virtual address for SGE * @next: nextChainOffset value (u32's) * @length: length of next SGL segment - * @dma_addr: Physical address + * @dma_addr: Physical address * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. @@ -986,7 +989,7 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) u32 tmp = dma_addr & 0xFFFFFFFF; pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); pChain->NextChainOffset = next; @@ -1283,7 +1286,7 @@ mpt_adapter_install(struct pci_dev *pdev) return r; if (!pci_set_dma_mask(pdev, mask)) { - dprintk((KERN_INFO MYNAM + dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); } else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); @@ -1470,6 +1473,12 @@ mpt_adapter_install(struct pci_dev *pdev) ioc->active = 0; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + /* tack onto tail of our MPT adapter list */ + Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER); + + /* Set lookup ptr. */ + mpt_adapters[ioc->id] = ioc; + ioc->pci_irq = -1; if (pdev->irq) { r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); @@ -1482,6 +1491,8 @@ mpt_adapter_install(struct pci_dev *pdev) printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", ioc->name, __irq_itoa(pdev->irq)); #endif + Q_DEL_ITEM(ioc); + mpt_adapters[ioc->id] = NULL; iounmap(mem); kfree(ioc); return -EBUSY; @@ -1498,16 +1509,10 @@ mpt_adapter_install(struct pci_dev *pdev) #endif } - /* tack onto tail of our MPT adapter list */ - Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER); - - /* Set lookup ptr. */ - mpt_adapters[ioc->id] = ioc; - /* NEW! 20010220 -sralston * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. */ - if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) + if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) mpt_detect_bound_ports(ioc, pdev); @@ -1638,6 +1643,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); /* Handle the alt IOC too */ if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ + ddlprintk((MYIOC_s_INFO_FMT + "Alt-ioc firmware upload required!\n", + ioc->name)); r = mpt_do_upload(ioc->alt_ioc, sleepFlag); if (r != 0) printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); @@ -1706,14 +1714,18 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) */ mpt_GetScsiPortSettings(ioc, 0); - /* Get version and length of SDP 1 + /* Get version and length of SDP 1 */ mpt_readScsiDevicePageHeaders(ioc, 0); - /* Find IM volumes + /* Find IM volumes */ if (ioc->facts.MsgVersion >= 0x0102) mpt_findImVolumes(ioc); + + /* Check, and possibly reset, the coalescing value + */ + mpt_read_ioc_pg_1(ioc); } GetIoUnitPage2(ioc); @@ -1819,7 +1831,7 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup) ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n")); if ((state = mpt_downloadboot(this, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM + printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", state); } } @@ -1919,6 +1931,11 @@ mpt_adapter_dispose(MPT_ADAPTER *this) sz_first = this->alloc_total; + if (this->alt_ioc != NULL) { + this->alt_ioc->alt_ioc = NULL; + this->alt_ioc = NULL; + } + mpt_adapter_disable(this, 1); if (this->pci_irq != -1) { @@ -1998,8 +2015,8 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc) * * Returns: * 1 - DIAG reset and READY - * 0 - READY initially OR soft reset and READY - * -1 - Any failure on KickStart + * 0 - READY initially OR soft reset and READY + * -1 - Any failure on KickStart * -2 - Msg Unit Reset Failed * -3 - IO Unit Reset Failed * -4 - IOC owned by a PEER @@ -2042,7 +2059,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) else statefault = 4; } - } + } /* * Check to see if IOC is in FAULT state. @@ -2244,7 +2261,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); /* - * FC f/w version changed between 1.1 and 1.2 + * FC f/w version changed between 1.1 and 1.2 * Old: u16{Major(4),Minor(4),SubMinor(8)} * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} */ @@ -2417,10 +2434,10 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE; - else + else ioc->upload_fw = 1; } - ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", + ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", ioc->name, ioc_init.Flags, ioc->upload_fw)); if ((int)ioc->chip_type <= (int)FC929) { @@ -2554,8 +2571,8 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) * Outputs: frags - number of fragments needed * Return NULL if failed. */ -void * -mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) +void * +mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) { fw_image_t **cached_fw = NULL; u8 *mem = NULL; @@ -2564,7 +2581,7 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) int bytes_left, bytes, num_frags; int sz, ii; - /* cached_fw + /* cached_fw */ sz = ioc->num_fw_frags * sizeof(void *); mem = kmalloc(sz, GFP_ATOMIC); @@ -2721,8 +2738,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1; ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32); - ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, - ioc->facts.FWImageSize, &num_frags, &alloc_sz); + ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, + ioc->facts.FWImageSize, &num_frags, &alloc_sz); if (ioc->cached_fw == NULL) { /* Major Failure. @@ -2769,8 +2786,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) sgeoffset += sizeof(u32) + sizeof(dma_addr_t); } - mpt_add_sge(&request[sgeoffset], - MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, + mpt_add_sge(&request[sgeoffset], + MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma); sgeoffset += sizeof(u32) + sizeof(dma_addr_t); @@ -3117,8 +3134,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) * 0 - no reset due to History bit, READY * -1 - no reset due to History bit but not READY * OR reset but failed to come READY - * -2 - no reset, could not enter DIAG mode - * -3 - reset but bad FW bit + * -2 - no reset, could not enter DIAG mode + * -3 - reset but bad FW bit */ static int KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) @@ -3254,18 +3271,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) ioc->name, diag0val, diag1val)); #endif /* Write the PreventIocBoot bit */ -#if 1 if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { -#else - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { -#endif diag0val |= MPI_DIAG_PREVENT_IOC_BOOT; CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); } /* * Disable the ARM (Bug fix) - * + * */ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); mdelay (1); @@ -3304,11 +3317,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* FIXME? Examine results here? */ } -#if 1 if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { -#else - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { -#endif /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 @@ -3318,7 +3327,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) #ifdef MPT_DEBUG if (ioc->alt_ioc) diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT + dprintk((MYIOC_s_INFO_FMT "DbG2b: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); #endif @@ -3335,7 +3344,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) } } if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) { - printk(KERN_WARNING MYNAM + printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", count); } @@ -3467,7 +3476,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) return r; - /* FW ACK'd request, wait for READY state + /* FW ACK'd request, wait for READY state */ cntdn = HZ * 15; count = 0; @@ -3631,6 +3640,9 @@ PrimeIocFifos(MPT_ADAPTER *ioc) } spin_unlock_irqrestore(&ioc->FreeQlock, flags); +#ifdef MFCNT + ioc->mfcnt = 0; +#endif if (ioc->sense_buf_pool == NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); @@ -4267,7 +4279,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) int ii; int data, rc = 0; - /* Allocate memory + /* Allocate memory */ if (!ioc->spi_data.nvram) { int sz; @@ -4446,12 +4458,17 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) ioc->spi_data.sdp0version = cfg.hdr->PageVersion; ioc->spi_data.sdp0length = cfg.hdr->PageLength; + dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n", + ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); + + dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n", + ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length)); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes + * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number * @@ -4464,17 +4481,13 @@ static int mpt_findImVolumes(MPT_ADAPTER *ioc) { IOCPage2_t *pIoc2 = NULL; - IOCPage3_t *pIoc3 = NULL; ConfigPageIoc2RaidVol_t *pIocRv = NULL; - u8 *mem; dma_addr_t ioc2_dma; - dma_addr_t ioc3_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; int jj; int rc = 0; int iocpage2sz; - int iocpage3sz = 0; u8 nVols, nPhys; u8 vid, vbus, vioc; @@ -4541,44 +4554,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* No physical disks. Done. */ } else { - /* There is at least one physical disk. - * Read and save IOC Page 3 - */ - header.PageVersion = 0; - header.PageLength = 0; - header.PageNumber = 3; - header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; - cfg.physAddr = -1; - cfg.pageAddr = 0; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; - cfg.timeout = 0; - if (mpt_config(ioc, &cfg) != 0) - goto done_and_free; - - if (header.PageLength == 0) - goto done_and_free; - - /* Read Header good, alloc memory - */ - iocpage3sz = header.PageLength * 4; - pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); - if (!pIoc3) - goto done_and_free; - - /* Read the Page and save the data - * into malloc'd memory. - */ - cfg.physAddr = ioc3_dma; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - if (mpt_config(ioc, &cfg) == 0) { - mem = kmalloc(iocpage3sz, GFP_ATOMIC); - if (mem) { - memcpy(mem, (u8 *)pIoc3, iocpage3sz); - ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; - } - } + mpt_read_ioc_pg_3(ioc); } done_and_free: @@ -4587,14 +4563,159 @@ done_and_free: pIoc2 = NULL; } + return rc; +} + +int +mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) +{ + IOCPage3_t *pIoc3 = NULL; + u8 *mem; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + dma_addr_t ioc3_dma; + int iocpage3sz = 0; + + /* Free the old page + */ + if (ioc->spi_data.pIocPg3) { + kfree(ioc->spi_data.pIocPg3); + ioc->spi_data.pIocPg3 = NULL; + } + + /* There is at least one physical disk. + * Read and save IOC Page 3 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 3; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return 0; + + if (header.PageLength == 0) + return 0; + + /* Read Header good, alloc memory + */ + iocpage3sz = header.PageLength * 4; + pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); + if (!pIoc3) + return 0; + + /* Read the Page and save the data + * into malloc'd memory. + */ + cfg.physAddr = ioc3_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + mem = kmalloc(iocpage3sz, GFP_ATOMIC); + if (mem) { + memcpy(mem, (u8 *)pIoc3, iocpage3sz); + ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; + } + } + if (pIoc3) { pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); pIoc3 = NULL; } - return rc; + return 0; } +static void +mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) +{ + IOCPage1_t *pIoc1 = NULL; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + dma_addr_t ioc1_dma; + int iocpage1sz = 0; + u32 tmp; + + /* Check the Coalescing Timeout in IOC Page 1 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 1; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return; + + if (header.PageLength == 0) + return; + + /* Read Header good, alloc memory + */ + iocpage1sz = header.PageLength * 4; + pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma); + if (!pIoc1) + return; + + /* Read the Page and check coalescing timeout + */ + cfg.physAddr = ioc1_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + + tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING; + if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) { + tmp = le32_to_cpu(pIoc1->CoalescingTimeout); + + dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n", + ioc->name, tmp)); + + if (tmp > MPT_COALESCING_TIMEOUT) { + pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT); + + /* Write NVRAM and current + */ + cfg.dir = 1; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n", + ioc->name, MPT_COALESCING_TIMEOUT)); + + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; + if (mpt_config(ioc, &cfg) == 0) { + dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n", + ioc->name, MPT_COALESCING_TIMEOUT)); + } else { + dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n", + ioc->name)); + } + + } else { + dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n", + ioc->name)); + } + } + + } else { + dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); + } + } + + if (pIoc1) { + pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); + pIoc1 = NULL; + } + + return; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -4690,7 +4811,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) */ in_isr = in_interrupt(); if (in_isr) { - dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", + dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", ioc->name)); return -EPERM; } @@ -4698,7 +4819,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { - dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", + dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", ioc->name)); return -EAGAIN; } @@ -4731,7 +4852,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); - dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); /* Append pCfg pointer to end of mf @@ -4778,7 +4899,7 @@ mpt_timer_expired(unsigned long data) { MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; - dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name)); + dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name)); /* Perform a FW reload */ if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) @@ -4788,7 +4909,7 @@ mpt_timer_expired(unsigned long data) * Hard reset clean-up will wake up * process and free all resources. */ - dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name)); + dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name)); return; } @@ -4829,7 +4950,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) } else { CONFIGPARMS *pNext; - /* Search the configQ for internal commands. + /* Search the configQ for internal commands. * Flush the Q, and wake up all suspended threads. */ #if 1 @@ -5096,8 +5217,7 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo */ if (isense_idx == ii) len += sprintf(buf+len, " Fusion MPT isense driver\n"); - } else - break; + } } MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); @@ -5774,6 +5894,7 @@ EXPORT_SYMBOL(mpt_lan_index); EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); +EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); @@ -5843,6 +5964,7 @@ static void fusion_exit(void) { MPT_ADAPTER *this; + struct pci_dev *pdev = NULL; dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); @@ -5861,9 +5983,14 @@ fusion_exit(void) this->active = 0; + pdev = (struct pci_dev *)this->pcidev; + mptscsih_sync_irq(pdev->irq); + /* Clear any lingering interrupt */ CHIPREG_WRITE32(&this->chip->IntStatus, 0); + CHIPREG_READ32(&this->chip->IntStatus); + Q_DEL_ITEM(this); mpt_adapter_dispose(this); } diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index c992a7f70379..916b3b299e3d 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -13,7 +13,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.h,v 1.136 2002/10/21 13:51:54 pdelaney Exp $ + * $Id: mptbase.h,v 1.141 2002/12/03 21:26:32 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -80,8 +80,8 @@ #define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "2.03.00.02" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.03.00.02" +#define MPT_LINUX_VERSION_COMMON "2.03.01.01" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.03.01.01" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -134,8 +134,10 @@ #define CAN_SLEEP 1 #define NO_SLEEP 0 -/* - * SCSI transfer rate defines. +#define MPT_COALESCING_TIMEOUT 0x10 + +/* + * SCSI transfer rate defines. */ #define MPT_ULTRA320 0x08 #define MPT_ULTRA160 0x09 @@ -524,7 +526,7 @@ typedef struct _mpt_ioctl_events { #define MPT_SCSICFG_DV_PENDING 0x04 /* DV on this physical id pending */ #define MPT_SCSICFG_DV_NOT_DONE 0x08 /* DV has not been performed */ #define MPT_SCSICFG_BLK_NEGO 0x10 /* WriteSDP1 with WDTR and SDTR disabled */ - +#define MPT_SCSICFG_RELOAD_IOC_PG3 0x20 /* IOC Pg 3 data is obsolete */ /* Args passed to writeSDP1: */ #define MPT_SCSICFG_USE_NVRAM 0x01 /* WriteSDP1 using NVRAM */ #define MPT_SCSICFG_ALL_IDS 0x02 /* WriteSDP1 to all IDS */ @@ -756,6 +758,12 @@ typedef struct _mpt_sge { #define nehprintk(x) #endif +#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG) +#define dcprintk(x) printk x +#else +#define dcprintk(x) +#endif + #define MPT_INDEX_2_MFPTR(ioc,idx) \ (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) ) @@ -1009,6 +1017,7 @@ extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); extern void *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img); +extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); /* * Public data decl's... diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 445afed79fd9..37b5799fd184 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -34,7 +34,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.c,v 1.61 2002/10/17 20:15:57 pdelaney Exp $ + * $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -2911,9 +2911,9 @@ int __init mptctl_init(void) #endif /*} sparc */ /* Register this device */ - if (misc_register(&mptctl_miscdev) == -1) { + err = misc_register(&mptctl_miscdev); + if (err < 0) { printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR); - err = -EBUSY; goto out_fail; } printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n"); diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index 444a5009c9ba..e7fedd5d38cb 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h @@ -20,7 +20,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $ + * $Id: mptctl.h,v 1.13 2002/12/03 21:26:33 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 57faa74cba29..965c1bb9636d 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -26,7 +26,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $ + * $Id: mptscsih.c,v 1.104 2002/12/03 21:26:34 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -159,11 +159,9 @@ typedef struct _dv_parameters { static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); -static int mptscsih_io_direction(Scsi_Cmnd *cmd); static int mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx); -static int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex); static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx); static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init); static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); @@ -274,6 +272,436 @@ static struct mptscsih_driver_setup /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * Private inline routines... + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 19991030 -sralston + * Return absolute SCSI data direction: + * 1 = _DATA_OUT + * 0 = _DIR_NONE + * -1 = _DATA_IN + * + * Changed: 3-20-2002 pdelaney to use the default data + * direction and the defines set up in the + * 2.4 kernel series + * 1 = _DATA_OUT changed to SCSI_DATA_WRITE (1) + * 0 = _DIR_NONE changed to SCSI_DATA_NONE (3) + * -1 = _DATA_IN changed to SCSI_DATA_READ (2) + * If the direction is unknown, fall through to original code. + * + * Mid-layer bug fix(): sg interface generates the wrong data + * direction in some cases. Set the direction the hard way for + * the most common commands. + */ +static inline int +mptscsih_io_direction(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + return SCSI_DATA_WRITE; + break; + case READ_6: + case READ_10: + return SCSI_DATA_READ; + break; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN) + return cmd->sc_data_direction; +#endif + switch (cmd->cmnd[0]) { + /* _DATA_OUT commands */ + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case REASSIGN_BLOCKS: + case PERSISTENT_RESERVE_OUT: + case 0xea: + case 0xa3: + return SCSI_DATA_WRITE; + + /* No data transfer commands */ + case SEEK_6: case SEEK_10: + case RESERVE: case RELEASE: + case TEST_UNIT_READY: + case START_STOP: + case ALLOW_MEDIUM_REMOVAL: + return SCSI_DATA_NONE; + + /* Conditional data transfer commands */ + case FORMAT_UNIT: + if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ + return SCSI_DATA_WRITE; + else + return SCSI_DATA_NONE; + + case VERIFY: + if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ + return SCSI_DATA_WRITE; + else + return SCSI_DATA_NONE; + + case RESERVE_10: + if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */ + return SCSI_DATA_WRITE; + else + return SCSI_DATA_NONE; + + /* Must be data _IN! */ + default: + return SCSI_DATA_READ; + } +} /* mptscsih_io_direction() */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_add_sge - Place a simple SGE at address pAddr. + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + */ +static inline void +mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + if (sizeof(dma_addr_t) == sizeof(u64)) { + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + u32 tmp = dma_addr & 0xFFFFFFFF; + + pSge->FlagsLength = cpu_to_le32(flagslength); + pSge->Address.Low = cpu_to_le32(tmp); + tmp = (u32) ((u64)dma_addr >> 32); + pSge->Address.High = cpu_to_le32(tmp); + + } else { + SGESimple32_t *pSge = (SGESimple32_t *) pAddr; + pSge->FlagsLength = cpu_to_le32(flagslength); + pSge->Address = cpu_to_le32(dma_addr); + } +} /* mptscsih_add_sge() */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_add_chain - Place a chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + */ +static inline void +mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + if (sizeof(dma_addr_t) == sizeof(u64)) { + SGEChain64_t *pChain = (SGEChain64_t *) pAddr; + u32 tmp = dma_addr & 0xFFFFFFFF; + + pChain->Length = cpu_to_le16(length); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); + + pChain->NextChainOffset = next; + + pChain->Address.Low = cpu_to_le32(tmp); + tmp = (u32) ((u64)dma_addr >> 32); + pChain->Address.High = cpu_to_le32(tmp); + } else { + SGEChain32_t *pChain = (SGEChain32_t *) pAddr; + pChain->Length = cpu_to_le16(length); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); + pChain->NextChainOffset = next; + pChain->Address = cpu_to_le32(dma_addr); + } +} /* mptscsih_add_chain() */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_getFreeChainBuffes - Function to get a free chain + * from the MPT_SCSI_HOST FreeChainQ. + * @hd: Pointer to the MPT_SCSI_HOST instance + * @req_idx: Index of the SCSI IO request frame. (output) + * + * return SUCCESS or FAILED + */ +static inline int +mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) +{ + MPT_FRAME_HDR *chainBuf = NULL; + unsigned long flags; + int rc = FAILED; + int chain_idx = MPT_HOST_NO_CHAIN; + + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + if (!Q_IS_EMPTY(&hd->FreeChainQ)) { + + int offset; + + chainBuf = hd->FreeChainQ.head; + Q_DEL_ITEM(&chainBuf->u.frame.linkage); + offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; + chain_idx = offset / hd->ioc->req_sz; + rc = SUCCESS; + } + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + + + *retIndex = chain_idx; + + dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", + hd->ioc->name, *retIndex, chainBuf)); + + return rc; +} /* mptscsih_getFreeChainBuffer() */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the + * SCSIIORequest_t Message Frame. + * @hd: Pointer to MPT_SCSI_HOST structure + * @SCpnt: Pointer to Scsi_Cmnd structure + * @pReq: Pointer to SCSIIORequest_t structure + * + * Returns ... + */ +static int +mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, + SCSIIORequest_t *pReq, int req_idx) +{ + char *psge; + char *chainSge; + struct scatterlist *sg; + int frm_sz; + int sges_left, sg_done; + int chain_idx = MPT_HOST_NO_CHAIN; + int sgeOffset; + int numSgeSlots, numSgeThisFrame; + u32 sgflags, sgdir, thisxfer = 0; + int chain_dma_off = 0; + int newIndex; + int ii; + dma_addr_t v2; + + sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; + if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { + sgdir = MPT_TRANSFER_HOST_TO_IOC; + } else { + sgdir = MPT_TRANSFER_IOC_TO_HOST; + } + + psge = (char *) &pReq->SGL; + frm_sz = hd->ioc->req_sz; + + /* Map the data portion, if any. + * sges_left = 0 if no data transfer. + */ + sges_left = SCpnt->use_sg; + if (SCpnt->use_sg) { + sges_left = pci_map_sg(hd->ioc->pcidev, + (struct scatterlist *) SCpnt->request_buffer, + SCpnt->use_sg, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else if (SCpnt->request_bufflen) { + dma_addr_t buf_dma_addr; + scPrivate *my_priv; + + buf_dma_addr = pci_map_single(hd->ioc->pcidev, + SCpnt->request_buffer, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* We hide it here for later unmap. */ + my_priv = (scPrivate *) &SCpnt->SCp; + my_priv->p1 = (void *)(ulong) buf_dma_addr; + + dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", + hd->ioc->name, SCpnt, SCpnt->request_bufflen)); + + mptscsih_add_sge((char *) &pReq->SGL, + 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen, + buf_dma_addr); + + return SUCCESS; + } + + /* Handle the SG case. + */ + sg = (struct scatterlist *) SCpnt->request_buffer; + sg_done = 0; + sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); + chainSge = NULL; + + /* Prior to entering this loop - the following must be set + * current MF: sgeOffset (bytes) + * chainSge (Null if original MF is not a chain buffer) + * sg_done (num SGE done for this MF) + */ + +nextSGEset: + numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); + numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; + + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; + + /* Get first (num - 1) SG elements + * Skip any SG entries with a length of 0 + * NOTE: at finish, sg and psge pointed to NEXT data/location positions + */ + for (ii=0; ii < (numSgeThisFrame-1); ii++) { + thisxfer = sg_dma_len(sg); + if (thisxfer == 0) { + sg ++; /* Get next SG element from the OS */ + sg_done++; + continue; + } + + v2 = sg_dma_address(sg); + mptscsih_add_sge(psge, sgflags | thisxfer, v2); + + sg++; /* Get next SG element from the OS */ + psge += (sizeof(u32) + sizeof(dma_addr_t)); + sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + sg_done++; + } + + if (numSgeThisFrame == sges_left) { + /* Add last element, end of buffer and end of list flags. + */ + sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT | + MPT_SGE_FLAGS_END_OF_BUFFER | + MPT_SGE_FLAGS_END_OF_LIST; + + /* Add last SGE and set termination flags. + * Note: Last SGE may have a length of 0 - which should be ok. + */ + thisxfer = sg_dma_len(sg); + + v2 = sg_dma_address(sg); + mptscsih_add_sge(psge, sgflags | thisxfer, v2); + /* + sg++; + psge += (sizeof(u32) + sizeof(dma_addr_t)); + */ + sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + sg_done++; + + if (chainSge) { + /* The current buffer is a chain buffer, + * but there is not another one. + * Update the chain element + * Offset and Length fields. + */ + mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + } else { + /* The current buffer is the original MF + * and there is no Chain buffer. + */ + pReq->ChainOffset = 0; + } + } else { + /* At least one chain buffer is needed. + * Complete the first MF + * - last SGE element, set the LastElement bit + * - set ChainOffset (words) for orig MF + * (OR finish previous MF chain buffer) + * - update MFStructPtr ChainIndex + * - Populate chain element + * Also + * Loop until done. + */ + + dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", + hd->ioc->name, sg_done)); + + /* Set LAST_ELEMENT flag for last non-chain element + * in the buffer. Since psge points at the NEXT + * SGE element, go back one SGE element, update the flags + * and reset the pointer. (Note: sgflags & thisxfer are already + * set properly). + */ + if (sg_done) { + u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); + sgflags = le32_to_cpu(*ptmp); + sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; + *ptmp = cpu_to_le32(sgflags); + } + + if (chainSge) { + /* The current buffer is a chain buffer. + * chainSge points to the previous Chain Element. + * Update its chain element Offset and Length (must + * include chain element size) fields. + * Old chain element is now complete. + */ + u8 nextChain = (u8) (sgeOffset >> 2); + sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off); + } else { + /* The original MF buffer requires a chain buffer - + * set the offset. + * Last element in this MF is a chain element. + */ + pReq->ChainOffset = (u8) (sgeOffset >> 2); + } + + sges_left -= sg_done; + + + /* NOTE: psge points to the beginning of the chain element + * in current buffer. Get a chain buffer. + */ + if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) + return FAILED; + + /* Update the tracking arrays. + * If chainSge == NULL, update ReqToChain, else ChainToChain + */ + if (chainSge) { + hd->ChainToChain[chain_idx] = newIndex; + } else { + hd->ReqToChain[req_idx] = newIndex; + } + chain_idx = newIndex; + chain_dma_off = hd->ioc->req_sz * chain_idx; + + /* Populate the chainSGE for the current buffer. + * - Set chain buffer pointer to psge and fill + * out the Address and Flags fields. + */ + chainSge = (char *) psge; + dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", + psge, req_idx)); + + /* Start the SGE for the next buffer + */ + psge = (char *) (hd->ChainBuffer + chain_dma_off); + sgeOffset = 0; + sg_done = 0; + + dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", + psge, chain_idx)); + + /* Start the SGE for the next buffer + */ + + goto nextSGEset; + } + + return SUCCESS; +} /* mptscsih_AddSGE() */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* * mptscsih_io_done - Main SCSI IO callback routine registered to * Fusion MPT (base) driver * @ioc: Pointer to MPT_ADAPTER structure @@ -294,7 +722,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) MPT_SCSI_HOST *hd; SCSIIORequest_t *pScsiReq; SCSIIOReply_t *pScsiReply; -#ifndef MPT_SCSI_USE_NEW_EH +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) unsigned long flags; #endif u16 req_idx; @@ -305,7 +733,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n", ioc->name, mf?"BAD":"NULL", (void *) mf); - /* return 1; CHECKME SteveR. Don't free. */ return 0; } @@ -411,12 +838,12 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) #ifndef MPT_SCSI_USE_NEW_EH search_taskQ_for_cmd(sc, hd); #endif - /* Linux handles an unsolicited DID_RESET better + /* Linux handles an unsolicited DID_RESET better * than an unsolicited DID_ABORT. */ sc->result = DID_RESET << 16; - /* GEM Workaround. */ + /* GEM Workaround. */ if (hd->is_spi) mptscsih_no_negotiate(hd, sc->target); break; @@ -428,7 +855,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) #endif sc->result = DID_RESET << 16; - /* GEM Workaround. */ + /* GEM Workaround. */ if (hd->is_spi) mptscsih_no_negotiate(hd, sc->target); break; @@ -506,7 +933,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ; } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* - * If running agains circa 200003dd 909 MPT f/w, + * If running against circa 200003dd 909 MPT f/w, * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL * (QUEUE_FULL) returned from device! --> get 0x0000?128 * and with SenseBytes set to 0. @@ -625,7 +1052,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) hd->ScsiLookup[req_idx] = NULL; - sc->host_scribble = NULL; /* CHECKME! - Do we need to clear this??? */ +#ifndef MPT_SCSI_USE_NEW_EH + sc->host_scribble = NULL; +#endif MPT_HOST_LOCK(flags); sc->scsi_done(sc); /* Issue the command callback */ @@ -894,7 +1323,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) int ii; int max = hd->ioc->req_depth; -#ifndef MPT_SCSI_USE_NEW_EH +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) unsigned long flags; #endif @@ -911,7 +1340,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) search_taskQ_for_cmd(SCpnt, hd); #endif - /* Search pendingQ, if found, + /* Search pendingQ, if found, * delete from Q. If found, do not decrement * queue_depth, command never posted. */ @@ -1061,7 +1490,7 @@ mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init) * of chain buffers to be allocated. * index = chain_idx * - * Calculate the number of chain buffers needed(plus 1) per I/O + * Calculate the number of chain buffers needed(plus 1) per I/O * then multiply the the maximum number of simultaneous cmds * * num_sge = num sge in request frame + last chain buffer @@ -1175,6 +1604,7 @@ mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIOReque /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int BeenHereDoneThat = 0; +static char *info_kbuf = NULL; /* SCSI host fops start here... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1263,9 +1693,10 @@ mptscsih_detect(Scsi_Host_Template *tpnt) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) tpnt->proc_dir = &proc_mpt_scsihost; #endif + tpnt->proc_info = mptscsih_proc_info; sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); if (sh != NULL) { - mptscsih_lock(this, flags); + spin_lock_irqsave(&this->FreeQlock, flags); sh->io_port = 0; sh->n_io_port = 0; sh->irq = 0; @@ -1326,7 +1757,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt) } else { numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale + (this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); - } + } if (numSGE < sh->sg_tablesize) { /* Reset this value */ @@ -1340,7 +1771,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt) */ scsi_set_pci_device(sh, this->pcidev); - mptscsih_unlock(this, flags); + spin_unlock_irqrestore(&this->FreeQlock, flags); hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = this; @@ -1503,12 +1934,25 @@ mptscsih_detect(Scsi_Host_Template *tpnt) done: if (mpt_scsi_hosts > 0) register_reboot_notifier(&mptscsih_notifier); + else { + mpt_reset_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n")); + + mpt_event_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); + + mpt_deregister(ScsiScanDvCtx); + mpt_deregister(ScsiTaskCtx); + mpt_deregister(ScsiDoneCtx); + + if (info_kbuf != NULL) + kfree(info_kbuf); + } return mpt_scsi_hosts; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static char *info_kbuf = NULL; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_release - Unregister SCSI host from linux scsi mid-layer @@ -1731,7 +2175,7 @@ mptscsih_halt(struct notifier_block *nb, ulong event, void *buf) const char * mptscsih_info(struct Scsi_Host *SChost) { - MPT_SCSI_HOST *h; + MPT_SCSI_HOST *h = NULL; int size = 0; if (info_kbuf == NULL) @@ -1740,12 +2184,307 @@ mptscsih_info(struct Scsi_Host *SChost) h = (MPT_SCSI_HOST *)SChost->hostdata; info_kbuf[0] = '\0'; - mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); - info_kbuf[size-1] = '\0'; + if (h) { + mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0); + info_kbuf[size-1] = '\0'; + } return info_kbuf; } +struct info_str { + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len) +{ + struct info_str info; + + info.buffer = pbuf; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name); + copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); + copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts); + copy_info(&info, "MaxQ=%d\n", ioc->req_depth); + + return ((info.pos > info.offset) ? info.pos - info.offset : 0); +} + +struct mptscsih_usrcmd { + ulong target; + ulong lun; + ulong data; + ulong cmd; +}; + +#define UC_GET_SPEED 0x10 + +static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc) +{ + CONFIGPARMS cfg; + dma_addr_t cfg_dma_addr = -1; + ConfigPageHeader_t header; + + dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n", + ioc, uc->cmd, uc->target)); + + switch (uc->cmd) { + case UC_GET_SPEED: + { + SCSIDevicePage0_t *pData = NULL; + + if (ioc->spi_data.sdp0length == 0) + return; + + pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev, + ioc->spi_data.sdp0length * 4, &cfg_dma_addr); + + if (pData == NULL) + return; + + header.PageVersion = ioc->spi_data.sdp0version; + header.PageLength = ioc->spi_data.sdp0length; + header.PageNumber = 0; + header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + + cfg.hdr = &header; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.dir = 0; + cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */ + cfg.physAddr = cfg_dma_addr; + + if (mpt_config(ioc, &cfg) == 0) { + u32 np = le32_to_cpu(pData->NegotiatedParameters); + u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE; + + printk("Target %d: %s;", + (u32) uc->target, + tmp ? "Wide" : "Narrow"); + + tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK; + if (tmp) { + u32 speed = 0; + printk(" Synchronous"); + tmp = (tmp >> 16); + printk(" (Offset=0x%x", tmp); + tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK; + tmp = (tmp >> 8); + printk(" Factor=0x%x)", tmp); + if (tmp <= MPT_ULTRA320) + speed=160; + else if (tmp <= MPT_ULTRA160) + speed=80; + else if (tmp <= MPT_ULTRA2) + speed=40; + else if (tmp <= MPT_ULTRA) + speed=20; + else if (tmp <= MPT_FAST) + speed=10; + else if (tmp <= MPT_SCSI) + speed=5; + + if (np & MPI_SCSIDEVPAGE0_NP_WIDE) + speed*=2; + + printk(" %dMB/sec\n", speed); + + } else + printk(" Asynchronous.\n"); + } else { + printk("failed\n" ); + } + + pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4, + pData, cfg_dma_addr); + } + break; + } +} + +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define digit_to_bin(c) ((c) - '0') +#define is_space(c) ((c) == ' ' || (c) == '\t') + +static int skip_spaces(char *ptr, int len) +{ + int cnt, c; + + for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --); + + return (len - cnt); +} + +static int get_int_arg(char *ptr, int len, ulong *pv) +{ + int cnt, c; + ulong v; + for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) { + v = (v * 10) + digit_to_bin(c); + } + + if (pv) + *pv = v; + + return (len - cnt); +} + + +static int is_keyword(char *ptr, int len, char *verb) +{ + int verb_len = strlen(verb); + + if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + return verb_len; + else + return 0; +} + +#define SKIP_SPACES(min_spaces) \ + if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \ + return -EINVAL; \ + ptr += arg_len; \ + len -= arg_len; + +#define GET_INT_ARG(v) \ + if (!(arg_len = get_int_arg(ptr,len, &(v)))) \ + return -EINVAL; \ + ptr += arg_len; \ + len -= arg_len; + +static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length) +{ + char *ptr = buffer; + struct mptscsih_usrcmd cmd, *uc = &cmd; + ulong target; + int arg_len; + int len = length; + + uc->target = uc->cmd = uc->lun = uc->data = 0; + + if ((len > 0) && (ptr[len -1] == '\n')) + --len; + + if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0) + uc->cmd = UC_GET_SPEED; + else + arg_len = 0; + + dprintk(("user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd)); + + if (!arg_len) + return -EINVAL; + + ptr += arg_len; + len -= arg_len; + + switch(uc->cmd) { + case UC_GET_SPEED: + SKIP_SPACES(1); + GET_INT_ARG(target); + uc->target = target; + break; + } + + dprintk(("user_command: target=%ld len=%d\n", uc->target, len)); + + if (len) + return -EINVAL; + else { + /* process this command ... + */ + mptscsih_exec_user_cmd(ioc, uc); + } + /* Not yet implemented */ + return length; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_proc_info - Return information about MPT adapter + * + * (linux Scsi_Host_Template.info routine) + * + * buffer: if write, user data; if read, buffer for user + * length: if write, return length; + * offset: if write, 0; if read, the current offset into the buffer from + * the previous read. + * hostno: scsi host number + * func: if write = 1; if read = 0 + */ +int mptscsih_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func) +{ + MPT_ADAPTER *ioc = NULL; + MPT_SCSI_HOST *hd = NULL; + int size = 0; + + dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func)); + dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n", + buffer, start, *start, offset, length)); + + for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { + if ((ioc->sh) && (ioc->sh->host_no == hostno)) { + hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + break; + } + } + if ((ioc == NULL) || (ioc->sh == NULL) || (hd == NULL)) + return 0; + + if (func) { + size = mptscsih_user_command(ioc, buffer, length); + } else { + if (start) + *start = buffer; + + size = mptscsih_host_info(ioc, buffer, offset, length); + } + + return size; +} + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int max_qd = 1; #if 0 @@ -1777,16 +2516,16 @@ static int numTMrequested = 0; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_put_msgframe - Wrapper routine to post message frame to F/W. - * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) - * @id: IOC id number - * @mf: Pointer to message frame + * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) + * @id: IOC id number + * @mf: Pointer to message frame * - * Handles the call to mptbase for posting request and queue depth + * Handles the call to mptbase for posting request and queue depth * tracking. * * Returns none. */ -static void +static inline void mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf) { /* Main banana... */ @@ -1973,12 +2712,11 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) /* * Write SCSI CDB into the message + * Should write from cmd_len up to 16, but skip for performance reasons. */ cmd_len = SCpnt->cmd_len; for (ii=0; ii < cmd_len; ii++) pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; - for (ii=cmd_len; ii < 16; ii++) - pScsiReq->CDB[ii] = 0; /* DataLength */ pScsiReq->DataLength = cpu_to_le32(datalen); @@ -1993,7 +2731,7 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) rc = SUCCESS; if (datalen == 0) { /* Add a NULL SGE */ - mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, + mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ @@ -2057,24 +2795,25 @@ mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION - if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) { + if ((dvStatus & MPT_SCSICFG_NEED_DV) || + (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) { unsigned long lflags; /* Schedule DV if necessary */ spin_lock_irqsave(&dvtaskQ_lock, lflags); if (!dvtaskQ_active) { dvtaskQ_active = 1; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); - MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); + MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); SCHEDULE_TASK(&mptscsih_dvTask); } else { spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } - hd->ioc->spi_data.forceDv = 0; + hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV; } /* Trying to do DV to this target, extend timeout. - * Wait to issue intil flag is clear + * Wait to issue intil flag is clear */ if (dvStatus & MPT_SCSICFG_DV_PENDING) { mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); @@ -2153,283 +2892,6 @@ did_error: /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the - * SCSIIORequest_t Message Frame. - * @hd: Pointer to MPT_SCSI_HOST structure - * @SCpnt: Pointer to Scsi_Cmnd structure - * @pReq: Pointer to SCSIIORequest_t structure - * - * Returns ... - */ -static int -mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt, - SCSIIORequest_t *pReq, int req_idx) -{ - char *psge; - char *chainSge; - struct scatterlist *sg; - int frm_sz; - int sges_left, sg_done; - int chain_idx = MPT_HOST_NO_CHAIN; - int sgeOffset; - int numSgeSlots, numSgeThisFrame; - u32 sgflags, sgdir, thisxfer = 0; - int chain_dma_off = 0; - int newIndex; - int ii; - dma_addr_t v2; - - sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; - if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { - sgdir = MPT_TRANSFER_HOST_TO_IOC; - } else { - sgdir = MPT_TRANSFER_IOC_TO_HOST; - } - - psge = (char *) &pReq->SGL; - frm_sz = hd->ioc->req_sz; - - /* Map the data portion, if any. - * sges_left = 0 if no data transfer. - */ - sges_left = SCpnt->use_sg; - if (SCpnt->use_sg) { - sges_left = pci_map_sg(hd->ioc->pcidev, - (struct scatterlist *) SCpnt->request_buffer, - SCpnt->use_sg, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - } else if (SCpnt->request_bufflen) { - dma_addr_t buf_dma_addr; - scPrivate *my_priv; - - buf_dma_addr = pci_map_single(hd->ioc->pcidev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - - /* We hide it here for later unmap. */ - my_priv = (scPrivate *) &SCpnt->SCp; - my_priv->p1 = (void *)(ulong) buf_dma_addr; - - dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", - hd->ioc->name, SCpnt, SCpnt->request_bufflen)); - - mpt_add_sge((char *) &pReq->SGL, - 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen, - buf_dma_addr); - - return SUCCESS; - } - - /* Handle the SG case. - */ - sg = (struct scatterlist *) SCpnt->request_buffer; - sg_done = 0; - sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); - chainSge = NULL; - - /* Prior to entering this loop - the following must be set - * current MF: sgeOffset (bytes) - * chainSge (Null if original MF is not a chain buffer) - * sg_done (num SGE done for this MF) - */ - -nextSGEset: - numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); - numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; - - sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; - - /* Get first (num - 1) SG elements - * Skip any SG entries with a length of 0 - * NOTE: at finish, sg and psge pointed to NEXT data/location positions - */ - for (ii=0; ii < (numSgeThisFrame-1); ii++) { - thisxfer = sg_dma_len(sg); - if (thisxfer == 0) { - sg ++; /* Get next SG element from the OS */ - sg_done++; - continue; - } - - v2 = sg_dma_address(sg); - mpt_add_sge(psge, sgflags | thisxfer, v2); - - sg++; /* Get next SG element from the OS */ - psge += (sizeof(u32) + sizeof(dma_addr_t)); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - sg_done++; - } - - if (numSgeThisFrame == sges_left) { - /* Add last element, end of buffer and end of list flags. - */ - sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT | - MPT_SGE_FLAGS_END_OF_BUFFER | - MPT_SGE_FLAGS_END_OF_LIST; - - /* Add last SGE and set termination flags. - * Note: Last SGE may have a length of 0 - which should be ok. - */ - thisxfer = sg_dma_len(sg); - - v2 = sg_dma_address(sg); - mpt_add_sge(psge, sgflags | thisxfer, v2); - /* - sg++; - psge += (sizeof(u32) + sizeof(dma_addr_t)); - */ - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - sg_done++; - - if (chainSge) { - /* The current buffer is a chain buffer, - * but there is not another one. - * Update the chain element - * Offset and Length fields. - */ - mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off); - } else { - /* The current buffer is the original MF - * and there is no Chain buffer. - */ - pReq->ChainOffset = 0; - } - } else { - /* At least one chain buffer is needed. - * Complete the first MF - * - last SGE element, set the LastElement bit - * - set ChainOffset (words) for orig MF - * (OR finish previous MF chain buffer) - * - update MFStructPtr ChainIndex - * - Populate chain element - * Also - * Loop until done. - */ - - dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", - hd->ioc->name, sg_done)); - - /* Set LAST_ELEMENT flag for last non-chain element - * in the buffer. Since psge points at the NEXT - * SGE element, go back one SGE element, update the flags - * and reset the pointer. (Note: sgflags & thisxfer are already - * set properly). - */ - if (sg_done) { - u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); - sgflags = le32_to_cpu(*ptmp); - sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; - *ptmp = cpu_to_le32(sgflags); - } - - if (chainSge) { - /* The current buffer is a chain buffer. - * chainSge points to the previous Chain Element. - * Update its chain element Offset and Length (must - * include chain element size) fields. - * Old chain element is now complete. - */ - u8 nextChain = (u8) (sgeOffset >> 2); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off); - } else { - /* The original MF buffer requires a chain buffer - - * set the offset. - * Last element in this MF is a chain element. - */ - pReq->ChainOffset = (u8) (sgeOffset >> 2); - } - - sges_left -= sg_done; - - - /* NOTE: psge points to the beginning of the chain element - * in current buffer. Get a chain buffer. - */ - if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) - return FAILED; - - /* Update the tracking arrays. - * If chainSge == NULL, update ReqToChain, else ChainToChain - */ - if (chainSge) { - hd->ChainToChain[chain_idx] = newIndex; - } else { - hd->ReqToChain[req_idx] = newIndex; - } - chain_idx = newIndex; - chain_dma_off = hd->ioc->req_sz * chain_idx; - - /* Populate the chainSGE for the current buffer. - * - Set chain buffer pointer to psge and fill - * out the Address and Flags fields. - */ - chainSge = (char *) psge; - dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", - psge, req_idx)); - - /* Start the SGE for the next buffer - */ - psge = (char *) (hd->ChainBuffer + chain_dma_off); - sgeOffset = 0; - sg_done = 0; - - dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", - psge, chain_idx)); - - /* Start the SGE for the next buffer - */ - - goto nextSGEset; - } - - return SUCCESS; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_getFreeChainBuffes - Function to get a free chain - * from the MPT_SCSI_HOST FreeChainQ. - * @hd: Pointer to the MPT_SCSI_HOST instance - * @req_idx: Index of the SCSI IO request frame. (output) - * - * return SUCCESS or FAILED - */ -static int -mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) -{ - MPT_FRAME_HDR *chainBuf = NULL; - unsigned long flags; - int rc = FAILED; - int chain_idx = MPT_HOST_NO_CHAIN; - - //spin_lock_irqsave(&hd->FreeChainQlock, flags); - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (!Q_IS_EMPTY(&hd->FreeChainQ)) { - - int offset; - - chainBuf = hd->FreeChainQ.head; - Q_DEL_ITEM(&chainBuf->u.frame.linkage); - offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; - chain_idx = offset / hd->ioc->req_sz; - rc = SUCCESS; - } - //spin_unlock_irqrestore(&hd->FreeChainQlock, flags); - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - - - *retIndex = chain_idx; - - dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", - hd->ioc->name, *retIndex, chainBuf)); - - return rc; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* * mptscsih_freeChainBuffers - Function to free chain buffers associated * with a SCSI IO request * @hd: Pointer to the MPT_SCSI_HOST instance @@ -2547,8 +3009,8 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, #ifdef MPT_DEBUG_RESET if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", + printk(MYIOC_s_WARN_FMT + "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", hd->ioc->name, ioc_raw_state); } #endif @@ -2765,7 +3227,7 @@ mptscsih_abort(Scsi_Cmnd * SCpnt) hd->abortSCpnt = SCpnt; if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) + SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) < 0) { /* The TM request failed and the subsequent FW-reload failed! @@ -2830,7 +3292,7 @@ mptscsih_dev_reset(Scsi_Cmnd * SCpnt) } if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - SCpnt->target, 0, 0, NO_SLEEP) + SCpnt->target, 0, 0, NO_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. @@ -2889,13 +3351,13 @@ mptscsih_bus_reset(Scsi_Cmnd * SCpnt) /* We are now ready to execute the task management request. */ if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - 0, 0, 0, NO_SLEEP) + 0, 0, 0, NO_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. */ - printk(MYIOC_s_WARN_FMT + printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n", hd->ioc->name, SCpnt); hd->tmPending = 0; @@ -2941,8 +3403,8 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt) if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){ status = FAILED; } else { - /* Make sure TM pending is cleared and TM state is set to - * NONE. + /* Make sure TM pending is cleared and TM state is set to + * NONE. */ hd->tmPending = 0; hd->tmState = TM_STATE_NONE; @@ -2958,7 +3420,7 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_tm_pending_wait - wait for pending task management request to + * mptscsih_tm_pending_wait - wait for pending task management request to * complete. * @hd: Pointer to MPT host structure. * @@ -3114,7 +3576,7 @@ mptscsih_old_abort(Scsi_Cmnd *SCpnt) * (bottom/unused portion of) MPT request frame. */ ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo; - MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); + MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); SCHEDULE_TASK(ptaskfoo); } else { @@ -3245,7 +3707,7 @@ mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) * (bottom/unused portion of) MPT request frame. */ ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo; - MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); + MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); SCHEDULE_TASK(ptaskfoo); } else { @@ -3599,7 +4061,7 @@ mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) * Called once per device the bus scan. Use it to force the queue_depth * member to 1 if a device does not support Q tags. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) int mptscsih_slave_configure(Scsi_Device *device) { @@ -3614,15 +4076,21 @@ mptscsih_slave_configure(Scsi_Device *device) if (!device->tagged_supported || !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { scsi_adjust_queue_depth(device, 0, 1); + + } else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) + && (pTarget->inq_data[0] & 0x1f) == 0x00 + && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) { + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_HIGH); } else { - scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - device->host->can_queue >> 1); + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_LOW); } } } return 0; } -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */ +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */ void mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList) { @@ -3648,113 +4116,32 @@ mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList) for (ii=0; ii < max; ii++) { pTarget = hd->Targets[ii]; - if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { + if (pTarget == NULL) { + continue; + } + if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { device->queue_depth = 1; + } else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) + && (pTarget->inq_data[0] & 0x1f) == 0x00 + && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) { + device->queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + } else { + device->queue_depth = MPT_SCSI_CMD_PER_DEV_LOW; } + dprintk((MYIOC_s_INFO_FMT + "target = %d, sync factor = %#x, queue depth = %d\n", + hd->ioc->name, pTarget->target_id, + pTarget->minSyncFactor, device->queue_depth)); } } } } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Private routines... */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* 19991030 -sralston - * Return absolute SCSI data direction: - * 1 = _DATA_OUT - * 0 = _DIR_NONE - * -1 = _DATA_IN - * - * Changed: 3-20-2002 pdelaney to use the default data - * direction and the defines set up in the - * 2.4 kernel series - * 1 = _DATA_OUT changed to SCSI_DATA_WRITE (1) - * 0 = _DIR_NONE changed to SCSI_DATA_NONE (3) - * -1 = _DATA_IN changed to SCSI_DATA_READ (2) - * If the direction is unknown, fall through to original code. - * - * Mid-layer bug fix(): sg interface generates the wrong data - * direction in some cases. Set the direction the hard way for - * the most common commands. - */ -static int -mptscsih_io_direction(Scsi_Cmnd *cmd) -{ - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - return SCSI_DATA_WRITE; - break; - case READ_6: - case READ_10: - return SCSI_DATA_READ; - break; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN) - return cmd->sc_data_direction; -#endif - switch (cmd->cmnd[0]) { - /* _DATA_OUT commands */ - case WRITE_6: case WRITE_10: case WRITE_12: - case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: - case WRITE_VERIFY: case WRITE_VERIFY_12: - case COMPARE: case COPY: case COPY_VERIFY: - case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: - case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: - case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: - case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: - case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: - case REASSIGN_BLOCKS: - case PERSISTENT_RESERVE_OUT: - case 0xea: - case 0xa3: - return SCSI_DATA_WRITE; - - /* No data transfer commands */ - case SEEK_6: case SEEK_10: - case RESERVE: case RELEASE: - case TEST_UNIT_READY: - case START_STOP: - case ALLOW_MEDIUM_REMOVAL: - return SCSI_DATA_NONE; - - /* Conditional data transfer commands */ - case FORMAT_UNIT: - if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ - return SCSI_DATA_WRITE; - else - return SCSI_DATA_NONE; - - case VERIFY: - if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ - return SCSI_DATA_WRITE; - else - return SCSI_DATA_NONE; - - case RESERVE_10: - if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */ - return SCSI_DATA_WRITE; - else - return SCSI_DATA_NONE; - -#if 0 - case REZERO_UNIT: /* (or REWIND) */ - case SPACE: - case ERASE: case ERASE_10: - case SYNCHRONIZE_CACHE: - case LOCK_UNLOCK_CACHE: -#endif - - /* Must be data _IN! */ - default: - return SCSI_DATA_READ; - } -} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* Utility function to copy sense data from the scsi_cmnd buffer @@ -3803,7 +4190,7 @@ copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply #ifdef ABORT_FIX if (sz >= SCSI_STD_SENSE_BYTES) { - if ((sense_data[02] == ABORTED_COMMAND) && + if ((sense_data[02] == ABORTED_COMMAND) && (sense_data[12] == 0x47) && (sense_data[13] == 0x00)){ target->numAborts++; if ((target->raidVolume == 0) && (target->numAborts > 5)) { @@ -3896,7 +4283,7 @@ SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* Search the pendingQ for a command with specific index. - * If found, delete and return mf pointer + * If found, delete and return mf pointer * If not found, return NULL */ static MPT_FRAME_HDR * @@ -4126,6 +4513,13 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n", ioc->name)); + + + /* 8. Set flag to force DV and re-read IOC Page 3 + */ + ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; + ddvtprintk(("Set reload IOC Pg3 Flag\n")); + } return 1; /* currently means nothing really */ @@ -4172,7 +4566,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_INTEGRATED_RAID: /* 0B */ #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION - /* negoNvram set to 0 if DV enabled and to USE_NVRAM if + /* negoNvram set to 0 if DV enabled and to USE_NVRAM if * if DV disabled. Need to check for target mode. */ hd = NULL; @@ -4188,11 +4582,12 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { - /* New or replaced disk. + /* New or replaced disk. * Set DV flag and schedule DV. */ pSpi = &ioc->spi_data; physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; + ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum)); if (pSpi->pIocPg3) { pPDisk = pSpi->pIocPg3->PhysDisk; numPDisk =pSpi->pIocPg3->NumPhysDisks; @@ -4207,6 +4602,16 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) pPDisk++; numPDisk--; } + + if (numPDisk == 0) { + /* The physical disk that needs DV was not found + * in the stored IOC Page 3. The driver must reload + * this page. DV routine will set the NEED_DV flag for + * all phys disks that have DV_NOT_DONE set. + */ + pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; + ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum)); + } } } } @@ -4670,7 +5075,7 @@ int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) if (ioop->cdbPtr == NULL) { return 0; } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) || - (ioop->cdbPtr[0] == CMD_ReadCapacity) || + (ioop->cdbPtr[0] == CMD_ReadCapacity) || (ioop->cdbPtr[0] == 0x43)) { return 0; } @@ -4794,7 +5199,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * } if (vdev && data) { - if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) || + if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) || ((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) { /* Copy the inquiry data - if we haven't yet. @@ -4877,7 +5282,7 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt factor = MPT_ULTRA320; /* If RAID, never disable QAS - * else if non RAID, do not disable + * else if non RAID, do not disable * QAS if bit 1 is set * bit 1 QAS support, non-raid only * bit 0 IU support @@ -5000,8 +5405,8 @@ static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) #endif /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. - * Else set the NEED_DV flag after Read Capacity Issued (disks) - * or Mode Sense (cdroms). + * Else set the NEED_DV flag after Read Capacity Issued (disks) + * or Mode Sense (cdroms). * * Tapes, initTarget will set this flag on completion of Inquiry command. * Called only if DV_NOT_DONE flag is set @@ -5037,7 +5442,7 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * If no Target, bus reset on 1st I/O. Set the flag to + * If no Target, bus reset on 1st I/O. Set the flag to * prevent any future negotiations to this device. */ static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id) @@ -5286,9 +5691,9 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) pData->Reserved = 0; pData->Configuration = cpu_to_le32(configuration); - dprintk((MYIOC_s_INFO_FMT + dprintk((MYIOC_s_INFO_FMT "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n", - ioc->name, id, (id | (bus<<8)), + ioc->name, id, (id | (bus<<8)), requested, configuration)); mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf); @@ -5327,8 +5732,8 @@ static void mptscsih_taskmgmt_timeout(unsigned long data) /* Because we have reset the IOC, no TM requests can be * pending. So let's make sure the tmPending flag is reset. */ - nehprintk((KERN_WARNING MYNAM - ": %s: mptscsih_taskmgmt_timeout\n", + nehprintk((KERN_WARNING MYNAM + ": %s: mptscsih_taskmgmt_timeout\n", hd->ioc->name)); hd->tmPending = 0; } @@ -5566,7 +5971,7 @@ static void mptscsih_timer_expired(unsigned long data) if (hd->tmPending) { spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); return; - } else + } else hd->tmPending = 1; spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); @@ -5645,7 +6050,7 @@ mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io) pReq->ActionDataWord = 0; /* Reserved for this action */ //pReq->ActionDataSGE = 0; - mpt_add_sge((char *)&pReq->ActionDataSGE, + mpt_add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", @@ -5974,7 +6379,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) if (id == hostId) id++; - /* Write SDP1 for all SCSI devices + /* Write SDP1 for all SCSI devices * Alloc memory and set up config buffer */ if (hd->is_spi) { @@ -6097,7 +6502,7 @@ mptscsih_domainValidation(void *arg) spin_unlock_irqrestore(&dvtaskQ_lock, flags); /* For this ioc, loop through all devices and do dv to each device. - * When complete with this ioc, search through the ioc list, and + * When complete with this ioc, search through the ioc list, and * for each scsi ioc found, do dv for all devices. Exit when no * device needs dv. */ @@ -6128,6 +6533,23 @@ mptscsih_domainValidation(void *arg) if (hd == NULL) continue; + if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) { + mpt_read_ioc_pg_3(ioc); + if (ioc->spi_data.pIocPg3) { + Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; + int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + + while (numPDisk) { + if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE) + ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV; + + pPDisk++; + numPDisk--; + } + } + ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3; + } + maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES); for (id = 0; id < maxid; id++) { @@ -6318,7 +6740,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) lun = 0; bus = 0; - ddvtprintk((MYIOC_s_NOTE_FMT + ddvtprintk((MYIOC_s_NOTE_FMT "DV started: numIOs %d bus=%d, id %d dv @ %p\n", ioc->name, atomic_read(&queue_depth), bus, id, &dv)); @@ -6423,7 +6845,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) /* Skip this ID? Set cfg.hdr to force config page write */ if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) && - (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { + (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", ioc->name, bus, id, lun)); @@ -6495,11 +6917,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) /* Wide - narrow - wide workaround case */ - if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) { + if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) { /* Send an untagged command to reset disk Qs corrupted * when a parity error occurs on a Request Sense. */ - if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) || + if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) || ((hd->ioc->facts.FWVersion.Word >= 0x01010000) && (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) { @@ -6535,7 +6957,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) rc = hd->pLocal->completion; if (rc == MPT_SCANDV_GOOD) { if (hd->pLocal->scsiStatus == STS_BUSY) { - retcode = 1; + if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0) + retcode = 1; + else + retcode = 0; + goto target_done; } } else if (rc == MPT_SCANDV_SENSE) { @@ -6607,7 +7033,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide * Resetart with a request for U160. */ - if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { + if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { doFallback = 1; } else { dv.cmd = MPT_UPDATE_MAX; @@ -6631,7 +7057,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) } - } else if (rc == MPT_SCANDV_ISSUE_SENSE) + } else if (rc == MPT_SCANDV_ISSUE_SENSE) doFallback = 1; /* set fallback flag */ else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE)) doFallback = 1; /* set fallback flag */ @@ -6871,7 +7297,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) mdelay (2000); notDone++; } else { - ddvprintk((MYIOC_s_INFO_FMT + ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.", ioc->name)); goto target_done; } @@ -6935,7 +7361,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) patt = -1; continue; } - } + } goto target_done; } else @@ -7048,7 +7474,7 @@ target_done: if (hd->pLocal->completion == MPT_SCANDV_GOOD) iocmd.flags &= ~MPT_ICFLAG_RESERVED; } else { - printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", + printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", ioc->name, id); } } @@ -7066,7 +7492,7 @@ target_done: mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); #if 0 - /* Double writes to SDP1 can cause problems, + /* Double writes to SDP1 can cause problems, * skip here since unnecessary */ /* Save the final negotiated settings to @@ -7222,7 +7648,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) case MPT_SET_MIN: ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ", hd->ioc->name)); - /* Set page to asynchronous and narrow + /* Set page to asynchronous and narrow * Do not update now, breaks fallback routine. */ width = MPT_NARROW; offset = 0; @@ -7244,7 +7670,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) case MPT_FALLBACK: ddvprintk((MYIOC_s_NOTE_FMT "Fallback: Start: offset %d, factor %x, width %d \n", - hd->ioc->name, dv->now.offset, + hd->ioc->name, dv->now.offset, dv->now.factor, dv->now.width)); width = dv->now.width; offset = dv->now.offset; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 885a1a55c0f1..6c78d41038c1 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -20,7 +20,7 @@ * (mailto:netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $ + * $Id: mptscsih.h,v 1.21 2002/12/03 21:26:35 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -73,9 +73,16 @@ * Try to keep these at 2^N-1 */ #define MPT_FC_CAN_QUEUE 63 -//#define MPT_SCSI_CAN_QUEUE 31 -#define MPT_SCSI_CAN_QUEUE MPT_FC_CAN_QUEUE -#define MPT_SCSI_CMD_PER_LUN 7 +#if defined MPT_SCSI_USE_NEW_EH + #define MPT_SCSI_CAN_QUEUE 127 +#else + #define MPT_SCSI_CAN_QUEUE 63 +#endif + +#define MPT_SCSI_CMD_PER_DEV_HIGH 31 +#define MPT_SCSI_CMD_PER_DEV_LOW 7 + +#define MPT_SCSI_CMD_PER_LUN 7 #define MPT_SCSI_MAX_SECTORS 8192 @@ -206,11 +213,16 @@ struct mptscsih_driver_setup #define x_scsi_dev_reset mptscsih_dev_reset #define x_scsi_host_reset mptscsih_host_reset #define x_scsi_bios_param mptscsih_bios_param -#define x_scsi_slave_configure mptscsih_slave_configure #define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh #define x_scsi_old_abort mptscsih_old_abort #define x_scsi_old_reset mptscsih_old_reset +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) +#define x_scsi_slave_configure mptscsih_slave_configure +#else +#define x_scsi_select_queue_depths mptscsih_select_queue_depths +#endif +#define x_scsi_proc_info mptscsih_proc_info /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -237,8 +249,14 @@ extern int x_scsi_bios_param(Disk *, struct block_device *, int *); #else extern int x_scsi_bios_param(Disk *, kdev_t, int *); #endif -extern int x_scsi_slave_configure(Scsi_Device *); extern void x_scsi_taskmgmt_bh(void *); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) +extern int x_scsi_slave_configure(Scsi_Device *); +#else +extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *); +#endif + +extern int x_scsi_proc_info(char *, char **, off_t, int, int, int); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) #define PROC_SCSI_DECL @@ -248,14 +266,19 @@ extern void x_scsi_taskmgmt_bh(void *); #ifdef MPT_SCSI_USE_NEW_EH -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) #define MPT_SCSIHOST { \ PROC_SCSI_DECL \ + .proc_info = x_scsi_proc_info, \ .name = "MPT SCSI Host", \ .detect = x_scsi_detect, \ .release = x_scsi_release, \ .info = x_scsi_info, \ + .command = NULL, \ + .queuecommand = x_scsi_queuecommand, \ + .slave_configure = x_scsi_slave_configure, \ + .eh_strategy_handler = NULL, \ .eh_abort_handler = x_scsi_abort, \ .eh_device_reset_handler = x_scsi_dev_reset, \ .eh_bus_reset_handler = x_scsi_bus_reset, \ @@ -275,6 +298,7 @@ extern void x_scsi_taskmgmt_bh(void *); #define MPT_SCSIHOST { \ .next = NULL, \ PROC_SCSI_DECL \ + .proc_info = x_scsi_proc_info, \ .name = "MPT SCSI Host", \ .detect = x_scsi_detect, \ .release = x_scsi_release, \ diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index cf64b44d706a..d86cb7b9e5f9 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1841,7 +1841,6 @@ ppp_register_channel(struct ppp_channel *chan) list_add(&pch->list, &new_channels); atomic_inc(&channel_count); spin_unlock_bh(&all_channels_lock); - MOD_INC_USE_COUNT; return 0; } @@ -1904,7 +1903,6 @@ ppp_unregister_channel(struct ppp_channel *chan) wake_up_interruptible(&pch->file.rwait); if (atomic_dec_and_test(&pch->file.refcnt)) ppp_destroy_channel(pch); - MOD_DEC_USE_COUNT; } /* diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 657786d3915e..311c09f18bf0 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -40,25 +40,18 @@ static struct pppox_proto *proto[PX_MAX_PROTO+1]; int register_pppox_proto(int proto_num, struct pppox_proto *pp) { - if (proto_num < 0 || proto_num > PX_MAX_PROTO) { + if (proto_num < 0 || proto_num > PX_MAX_PROTO) return -EINVAL; - } - if (proto[proto_num]) return -EALREADY; - - MOD_INC_USE_COUNT; - proto[proto_num] = pp; return 0; } void unregister_pppox_proto(int proto_num) { - if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) { + if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) proto[proto_num] = NULL; - MOD_DEC_USE_COUNT; - } } void pppox_unbind_sock(struct sock *sk) diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 8bbb4666246d..470c637dfb8f 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -95,7 +95,6 @@ slhc_init(int rslots, int tslots) register struct cstate *ts; struct slcompress *comp; - MOD_INC_USE_COUNT; comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) @@ -147,7 +146,6 @@ out_free2: out_free: kfree((unsigned char *)comp); out_fail: - MOD_DEC_USE_COUNT; return NULL; } @@ -166,7 +164,6 @@ slhc_free(struct slcompress *comp) kfree( comp->rstate ); kfree( comp ); - MOD_DEC_USE_COUNT; } @@ -685,7 +682,6 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) return isize; } - int slhc_toss(struct slcompress *comp) { diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile index 2cdcc59b3cff..48261d04ecbc 100644 --- a/drivers/video/i810/Makefile +++ b/drivers/video/i810/Makefile @@ -18,5 +18,3 @@ i810fb-objs += i810_gtf.o else i810fb-objs += i810_dvt.o endif - -include $(TOPDIR)/Rules.make diff --git a/fs/adfs/super.c b/fs/adfs/super.c index e76d73e204c4..bc3e040de140 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -18,6 +18,7 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/bitops.h> #include <asm/uaccess.h> diff --git a/fs/affs/super.c b/fs/affs/super.c index 340b1b21388a..ebc0fb917744 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 9ef5130f12f6..dc0eb28dd0e9 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -12,6 +12,7 @@ #include <linux/stat.h> #include <linux/nls.h> #include <linux/buffer_head.h> +#include <linux/statfs.h> #include "befs.h" #include "btree.h" diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 49895016e770..0a41ab302781 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -12,6 +12,7 @@ #include <linux/fs.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/uaccess.h> #include "bfs.h" diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f75c61caac87..4bcb8b672f4f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -31,6 +31,7 @@ #include <linux/version.h> #include <linux/list.h> #include <linux/seq_file.h> +#include <linux/vfs.h> #include "cifsfs.h" #include "cifspdu.h" #define DECLARE_GLOBALS_HERE diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index cd8a7b42419d..0255c7fccad5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -22,6 +22,8 @@ #define _CIFSPROTO_H #include <linux/nls.h> +struct statfs; + /* ***************************************************************** * All Prototypes diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e1aca86ab253..65e792383571 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -25,6 +25,7 @@ #include <linux/fs.h> #include <linux/kernel.h> +#include <linux/vfs.h> #include <asm/uaccess.h> #include "cifspdu.h" #include "cifsglob.h" diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 763498ed9b09..690806872b10 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -17,6 +17,7 @@ #include <linux/unistd.h> #include <linux/smp_lock.h> #include <linux/file.h> +#include <linux/vfs.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 221bfb88ed4a..9a15dedc8d8a 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -29,6 +29,7 @@ #include <linux/string.h> #include <asm/uaccess.h> #include <linux/vmalloc.h> +#include <linux/vfs.h> #include <linux/coda.h> #include <linux/coda_linux.h> diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 8bdc09c05fe3..0152d61b1268 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/cramfs_fs_sb.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/semaphore.h> #include <asm/uaccess.h> diff --git a/fs/devfs/base.c b/fs/devfs/base.c index b4cbba51d30e..e3c8c13b7bfd 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -1764,29 +1764,6 @@ devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info) } /* End Function devfs_mk_dir */ -/** - * devfs_get_handle - Find the handle of a devfs entry. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * name is relative to the root of the devfs. - * @name: The name of the entry. - * @traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are - * traversed. Symlinks pointing out of the devfs namespace will cause a - * failure. Symlink traversal consumes stack space. - * - * Returns a handle which may later be used in a call to - * devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A - * subsequent devfs_put() is required to decrement the refcount. - * On failure %NULL is returned. - */ - -devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name, - int traverse_symlinks) -{ - if (!name || !name[0]) - return NULL; - return _devfs_find_entry (dir, name, traverse_symlinks); -} /* End Function devfs_get_handle */ - void devfs_remove(const char *fmt, ...) { char buf[64]; @@ -1795,27 +1772,13 @@ void devfs_remove(const char *fmt, ...) va_start(args, fmt); n = vsnprintf(buf, 64, fmt, args); - if (n < 64) { - devfs_handle_t de = devfs_get_handle(NULL, buf, 0); + if (n < 64 && buf[0]) { + devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); devfs_unregister(de); devfs_put(de); } } -/** - * devfs_get_handle_from_inode - Get the devfs handle for a VFS inode. - * @inode: The VFS inode. - * - * Returns the devfs handle on success, else %NULL. - */ - -devfs_handle_t devfs_get_handle_from_inode (struct inode *inode) -{ - if (!inode || !inode->i_sb) return NULL; - if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL; - return get_devfs_entry_from_vfs_inode (inode); -} /* End Function devfs_get_handle_from_inode */ - /** * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. @@ -1906,97 +1869,6 @@ int devfs_set_file_size (devfs_handle_t de, unsigned long size) /** - * devfs_get_info - Get the info pointer written to private_data of @de upon open. - * @de: The handle to the device entry. - * - * Returns the info pointer. - */ -void *devfs_get_info (devfs_handle_t de) -{ - if (de == NULL) return NULL; - VERIFY_ENTRY (de); - return de->info; -} /* End Function devfs_get_info */ - - -/** - * devfs_set_info - Set the info pointer written to private_data upon open. - * @de: The handle to the device entry. - * @info: pointer to the data - * - * Returns 0 on success, else a negative error code. - */ -int devfs_set_info (devfs_handle_t de, void *info) -{ - if (de == NULL) return -EINVAL; - VERIFY_ENTRY (de); - de->info = info; - return 0; -} /* End Function devfs_set_info */ - - -/** - * devfs_get_parent - Get the parent device entry. - * @de: The handle to the device entry. - * - * Returns the parent device entry if it exists, else %NULL. - */ -devfs_handle_t devfs_get_parent (devfs_handle_t de) -{ - if (de == NULL) return NULL; - VERIFY_ENTRY (de); - return de->parent; -} /* End Function devfs_get_parent */ - - -/** - * devfs_get_first_child - Get the first leaf node in a directory. - * @de: The handle to the device entry. - * - * Returns the leaf node device entry if it exists, else %NULL. - */ - -devfs_handle_t devfs_get_first_child (devfs_handle_t de) -{ - if (de == NULL) return NULL; - VERIFY_ENTRY (de); - if ( !S_ISDIR (de->mode) ) return NULL; - return de->u.dir.first; -} /* End Function devfs_get_first_child */ - - -/** - * devfs_get_next_sibling - Get the next sibling leaf node. for a device entry. - * @de: The handle to the device entry. - * - * Returns the leaf node device entry if it exists, else %NULL. - */ - -devfs_handle_t devfs_get_next_sibling (devfs_handle_t de) -{ - if (de == NULL) return NULL; - VERIFY_ENTRY (de); - return de->next; -} /* End Function devfs_get_next_sibling */ - -/** - * devfs_get_name - Get the name for a device entry in its parent directory. - * @de: The handle to the device entry. - * @namelen: The length of the name is written here. This may be %NULL. - * - * Returns the name on success, else %NULL. - */ - -const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen) -{ - if (de == NULL) return NULL; - VERIFY_ENTRY (de); - if (namelen != NULL) *namelen = de->namelen; - return de->name; -} /* End Function devfs_get_name */ - - -/** * devfs_only - returns true if "devfs=only" is a boot option * * If "devfs=only" this function will return 1, otherwise 0 is returned. @@ -2079,17 +1951,8 @@ EXPORT_SYMBOL(devfs_register); EXPORT_SYMBOL(devfs_unregister); EXPORT_SYMBOL(devfs_mk_symlink); EXPORT_SYMBOL(devfs_mk_dir); -EXPORT_SYMBOL(devfs_get_handle); EXPORT_SYMBOL(devfs_remove); -EXPORT_SYMBOL(devfs_get_handle_from_inode); EXPORT_SYMBOL(devfs_generate_path); -EXPORT_SYMBOL(devfs_set_file_size); -EXPORT_SYMBOL(devfs_get_info); -EXPORT_SYMBOL(devfs_set_info); -EXPORT_SYMBOL(devfs_get_parent); -EXPORT_SYMBOL(devfs_get_first_child); -EXPORT_SYMBOL(devfs_get_next_sibling); -EXPORT_SYMBOL(devfs_get_name); EXPORT_SYMBOL(devfs_only); diff --git a/fs/dquot.c b/fs/dquot.c index cfef15182227..21ba3cd19783 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -49,6 +49,9 @@ * formats registering. * Jan Kara, <jack@suse.cz>, 2001,2002 * + * New SMP locking. + * Jan Kara, <jack@suse.cz>, 10/2002 + * * (C) Copyright 1994 - 1997 Marco van Wieringen */ @@ -74,15 +77,32 @@ #include <asm/uaccess.h> +#define __DQUOT_PARANOIA + +/* + * There are two quota SMP locks. dq_list_lock protects all lists with quotas + * and quota formats and also dqstats structure containing statistics about the + * lists. dq_data_lock protects data from dq_dqb and also mem_dqinfo structures + * and also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes. + * Note that we don't have to do the locking of i_blocks and i_bytes when the + * quota is disabled - i_sem should serialize the access. dq_data_lock should + * be always grabbed before dq_list_lock. + * + * Note that some things (eg. sb pointer, type, id) doesn't change during + * the life of the dquot structure and so needn't to be protected by a lock + */ +spinlock_t dq_list_lock = SPIN_LOCK_UNLOCKED; +spinlock_t dq_data_lock = SPIN_LOCK_UNLOCKED; + static char *quotatypes[] = INITQFNAMES; static struct quota_format_type *quota_formats; /* List of registered formats */ int register_quota_format(struct quota_format_type *fmt) { - lock_kernel(); + spin_lock(&dq_list_lock); fmt->qf_next = quota_formats; quota_formats = fmt; - unlock_kernel(); + spin_unlock(&dq_list_lock); return 0; } @@ -90,22 +110,22 @@ void unregister_quota_format(struct quota_format_type *fmt) { struct quota_format_type **actqf; - lock_kernel(); + spin_lock(&dq_list_lock); for (actqf = "a_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next); if (*actqf) *actqf = (*actqf)->qf_next; - unlock_kernel(); + spin_unlock(&dq_list_lock); } static struct quota_format_type *find_quota_format(int id) { struct quota_format_type *actqf; - lock_kernel(); + spin_lock(&dq_list_lock); for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); if (actqf && !try_module_get(actqf->qf_owner)) actqf = NULL; - unlock_kernel(); + spin_unlock(&dq_list_lock); return actqf; } @@ -136,18 +156,20 @@ static void put_quota_format(struct quota_format_type *fmt) */ /* - * Note that any operation which operates on dquot data (ie. dq_dqb) mustn't - * block while it's updating/reading it. Otherwise races would occur. + * Note that any operation which operates on dquot data (ie. dq_dqb) must + * hold dq_data_lock. * - * Locked dquots might not be referenced in inodes - operations like - * add_dquot_space() does dqduplicate() and would complain. Currently - * dquot it locked only once in its existence - when it's being read - * to memory on first dqget() and at that time it can't be referenced - * from inode. Write operations on dquots don't hold dquot lock as they - * copy data to internal buffers before writing anyway and copying as well - * as any data update should be atomic. Also nobody can change used - * entries in dquot structure as this is done only when quota is destroyed - * and invalidate_dquots() waits for dquot to have dq_count == 0. + * Any operation working with dquots must hold dqoff_sem. If operation is + * just reading pointers from inodes than read lock is enough. If pointers + * are altered function must hold write lock. + * + * Locked dquots might not be referenced in inodes. Currently dquot it locked + * only once in its existence - when it's being read to memory on first dqget() + * and at that time it can't be referenced from inode. Write operations on + * dquots don't hold dquot lock as they copy data to internal buffers before + * writing anyway and copying as well as any data update should be atomic. Also + * nobody can change used entries in dquot structure as this is done only when + * quota is destroyed and invalidate_dquots() is called only when dq_count == 0. */ static LIST_HEAD(inuse_list); @@ -156,34 +178,14 @@ static struct list_head dquot_hash[NR_DQHASH]; struct dqstats dqstats; -static void dqput(struct dquot *); -static struct dquot *dqduplicate(struct dquot *); - -static inline void get_dquot_ref(struct dquot *dquot) -{ - dquot->dq_count++; -} - -static inline void put_dquot_ref(struct dquot *dquot) -{ - dquot->dq_count--; -} - -static inline void get_dquot_dup_ref(struct dquot *dquot) -{ - dquot->dq_dup_ref++; -} - -static inline void put_dquot_dup_ref(struct dquot *dquot) -{ - dquot->dq_dup_ref--; -} - static inline int const hashfn(struct super_block *sb, unsigned int id, int type) { return((((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; } +/* + * Following list functions expect dq_list_lock to be held + */ static inline void insert_dquot_hash(struct dquot *dquot) { struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); @@ -208,13 +210,6 @@ static inline struct dquot *find_dquot(unsigned int hashent, struct super_block return NODQUOT; } -/* Add a dquot to the head of the free list */ -static inline void put_dquot_head(struct dquot *dquot) -{ - list_add(&dquot->dq_free, &free_dquots); - dqstats.free_dquots++; -} - /* Add a dquot to the tail of the free list */ static inline void put_dquot_last(struct dquot *dquot) { @@ -222,13 +217,6 @@ static inline void put_dquot_last(struct dquot *dquot) dqstats.free_dquots++; } -/* Move dquot to the head of free list (it must be already on it) */ -static inline void move_dquot_head(struct dquot *dquot) -{ - list_del(&dquot->dq_free); - list_add(&dquot->dq_free, &free_dquots); -} - static inline void remove_free_dquot(struct dquot *dquot) { if (list_empty(&dquot->dq_free)) @@ -251,69 +239,10 @@ static inline void remove_inuse(struct dquot *dquot) list_del(&dquot->dq_inuse); } -static void __wait_on_dquot(struct dquot *dquot) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&dquot->dq_wait_lock, &wait); -repeat: - set_current_state(TASK_UNINTERRUPTIBLE); - if (dquot->dq_flags & DQ_LOCKED) { - schedule(); - goto repeat; - } - remove_wait_queue(&dquot->dq_wait_lock, &wait); - current->state = TASK_RUNNING; -} - -static inline void wait_on_dquot(struct dquot *dquot) -{ - if (dquot->dq_flags & DQ_LOCKED) - __wait_on_dquot(dquot); -} - -static inline void lock_dquot(struct dquot *dquot) +static void wait_on_dquot(struct dquot *dquot) { - wait_on_dquot(dquot); - dquot->dq_flags |= DQ_LOCKED; -} - -static inline void unlock_dquot(struct dquot *dquot) -{ - dquot->dq_flags &= ~DQ_LOCKED; - wake_up(&dquot->dq_wait_lock); -} - -/* Wait for dquot to be unused */ -static void __wait_dquot_unused(struct dquot *dquot) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&dquot->dq_wait_free, &wait); -repeat: - set_current_state(TASK_UNINTERRUPTIBLE); - if (dquot->dq_count) { - schedule(); - goto repeat; - } - remove_wait_queue(&dquot->dq_wait_free, &wait); - current->state = TASK_RUNNING; -} - -/* Wait for all duplicated dquot references to be dropped */ -static void __wait_dup_drop(struct dquot *dquot) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&dquot->dq_wait_free, &wait); -repeat: - set_current_state(TASK_UNINTERRUPTIBLE); - if (dquot->dq_dup_ref) { - schedule(); - goto repeat; - } - remove_wait_queue(&dquot->dq_wait_free, &wait); - current->state = TASK_RUNNING; + down(&dquot->dq_lock); + up(&dquot->dq_lock); } static int read_dqblk(struct dquot *dquot) @@ -321,11 +250,11 @@ static int read_dqblk(struct dquot *dquot) int ret; struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); - lock_dquot(dquot); + down(&dquot->dq_lock); down(&dqopt->dqio_sem); ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot); up(&dqopt->dqio_sem); - unlock_dquot(dquot); + up(&dquot->dq_lock); return ret; } @@ -340,36 +269,35 @@ static int commit_dqblk(struct dquot *dquot) return ret; } -/* Invalidate all dquots on the list, wait for all users. Note that this function is called - * after quota is disabled so no new quota might be created. As we only insert to the end of - * inuse list, we don't have to restart searching... */ +/* Invalidate all dquots on the list. Note that this function is called after + * quota is disabled so no new quota might be created. Because we hold dqoff_sem + * for writing and pointers were already removed from inodes we actually know that + * no quota for this sb+type should be held. */ static void invalidate_dquots(struct super_block *sb, int type) { struct dquot *dquot; struct list_head *head; -restart: - list_for_each(head, &inuse_list) { + spin_lock(&dq_list_lock); + for (head = inuse_list.next; head != &inuse_list;) { dquot = list_entry(head, struct dquot, dq_inuse); + head = head->next; if (dquot->dq_sb != sb) continue; if (dquot->dq_type != type) continue; - dquot->dq_flags |= DQ_INVAL; - if (dquot->dq_count) - /* - * Wait for any users of quota. As we have already cleared the flags in - * superblock and cleared all pointers from inodes we are assured - * that there will be no new users of this quota. - */ - __wait_dquot_unused(dquot); +#ifdef __DQUOT_PARANOIA + /* There should be no users of quota - we hold dqoff_sem for writing */ + if (atomic_read(&dquot->dq_count)) + BUG(); +#endif /* Quota now have no users and it has been written on last dqput() */ remove_dquot_hash(dquot); remove_free_dquot(dquot); remove_inuse(dquot); kmem_cache_free(dquot_cachep, dquot); - goto restart; } + spin_unlock(&dq_list_lock); } static int vfs_quota_sync(struct super_block *sb, int type) @@ -379,7 +307,14 @@ static int vfs_quota_sync(struct super_block *sb, int type) struct quota_info *dqopt = sb_dqopt(sb); int cnt; + down_read(&dqopt->dqoff_sem); restart: + /* At this point any dirty dquot will definitely be written so we can clear + dirty flag from info */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)) + clear_bit(DQF_ANY_DQUOT_DIRTY_B, &dqopt->info[cnt].dqi_flags); + spin_lock(&dq_list_lock); list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); if (sb && dquot->dq_sb != sb) @@ -388,26 +323,24 @@ restart: continue; if (!dquot->dq_sb) /* Invalidated? */ continue; - if (!dquot_dirty(dquot) && !(dquot->dq_flags & DQ_LOCKED)) + if (!dquot_dirty(dquot)) continue; - /* Get reference to quota so it won't be invalidated. get_dquot_ref() - * is enough since if dquot is locked/modified it can't be - * on the free list */ - get_dquot_ref(dquot); - if (dquot->dq_flags & DQ_LOCKED) - wait_on_dquot(dquot); - if (dquot_dirty(dquot)) - commit_dqblk(dquot); - dqput(dquot); + spin_unlock(&dq_list_lock); + commit_dqblk(dquot); goto restart; } + spin_unlock(&dq_list_lock); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)) - dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY; - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) { + down(&dqopt->dqio_sem); dqopt->ops[cnt]->write_file_info(sb, cnt); + up(&dqopt->dqio_sem); + } + spin_lock(&dq_list_lock); dqstats.syncs++; + spin_unlock(&dq_list_lock); + up_read(&dqopt->dqoff_sem); return 0; } @@ -424,7 +357,7 @@ restart: for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) - && sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY) + && info_any_dquot_dirty(&sb_dqopt(sb)->info[cnt])) dirty = 1; if (!dirty) continue; @@ -444,17 +377,13 @@ restart: void sync_dquots(struct super_block *sb, int type) { if (sb) { - lock_kernel(); if (sb->s_qcop->quota_sync) sb->s_qcop->quota_sync(sb, type); - unlock_kernel(); } else { while ((sb = get_super_to_sync(type))) { - lock_kernel(); if (sb->s_qcop->quota_sync) sb->s_qcop->quota_sync(sb, type); - unlock_kernel(); drop_super(sb); } } @@ -485,60 +414,60 @@ static void prune_dqcache(int count) static int shrink_dqcache_memory(int nr, unsigned int gfp_mask) { - if (nr) { - lock_kernel(); + int ret; + + spin_lock(&dq_list_lock); + if (nr) prune_dqcache(nr); - unlock_kernel(); - } - return dqstats.allocated_dquots; + ret = dqstats.allocated_dquots; + spin_unlock(&dq_list_lock); + return ret; } /* * Put reference to dquot * NOTE: If you change this function please check whether dqput_blocks() works right... + * MUST be called with dqoff_sem held */ static void dqput(struct dquot *dquot) { if (!dquot) return; #ifdef __DQUOT_PARANOIA - if (!dquot->dq_count) { + if (!atomic_read(&dquot->dq_count)) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", dquot->dq_sb->s_id, quotatypes[dquot->dq_type], dquot->dq_id); - return; + BUG(); } #endif - + + spin_lock(&dq_list_lock); dqstats.drops++; + spin_unlock(&dq_list_lock); we_slept: - if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) { /* Last unduplicated reference? */ - __wait_dup_drop(dquot); - goto we_slept; - } - if (dquot->dq_count > 1) { - /* We have more than one user... We can simply decrement use count */ - put_dquot_ref(dquot); + spin_lock(&dq_list_lock); + if (atomic_read(&dquot->dq_count) > 1) { + /* We have more than one user... nothing to do */ + atomic_dec(&dquot->dq_count); + spin_unlock(&dq_list_lock); return; } if (dquot_dirty(dquot)) { + spin_unlock(&dq_list_lock); commit_dqblk(dquot); goto we_slept; } - + atomic_dec(&dquot->dq_count); +#ifdef __DQUOT_PARANOIA /* sanity check */ - if (!list_empty(&dquot->dq_free)) { - printk(KERN_ERR "dqput: dquot already on free list??\n"); - put_dquot_ref(dquot); - return; - } - put_dquot_ref(dquot); - /* If dquot is going to be invalidated invalidate_dquots() is going to free it so */ - if (!(dquot->dq_flags & DQ_INVAL)) - put_dquot_last(dquot); /* Place at end of LRU free queue */ - wake_up(&dquot->dq_wait_free); + if (!list_empty(&dquot->dq_free)) + BUG(); +#endif + put_dquot_last(dquot); + spin_unlock(&dq_list_lock); } static struct dquot *get_empty_dquot(struct super_block *sb, int type) @@ -550,99 +479,66 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) return NODQUOT; memset((caddr_t)dquot, 0, sizeof(struct dquot)); - init_waitqueue_head(&dquot->dq_wait_free); - init_waitqueue_head(&dquot->dq_wait_lock); + sema_init(&dquot->dq_lock, 1); INIT_LIST_HEAD(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_inuse); INIT_LIST_HEAD(&dquot->dq_hash); dquot->dq_sb = sb; dquot->dq_type = type; - dquot->dq_count = 1; - /* all dquots go on the inuse_list */ - put_inuse(dquot); + atomic_set(&dquot->dq_count, 1); return dquot; } +/* + * Get reference to dquot + * MUST be called with dqoff_sem held + */ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) { unsigned int hashent = hashfn(sb, id, type); struct dquot *dquot, *empty = NODQUOT; - struct quota_info *dqopt = sb_dqopt(sb); + if (!sb_has_quota_enabled(sb, type)) + return NODQUOT; we_slept: - if (!is_enabled(dqopt, type)) { - if (empty) - dqput(empty); - return NODQUOT; - } - + spin_lock(&dq_list_lock); if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { if (empty == NODQUOT) { + spin_unlock(&dq_list_lock); if ((empty = get_empty_dquot(sb, type)) == NODQUOT) schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; dquot->dq_id = id; + /* all dquots go on the inuse_list */ + put_inuse(dquot); /* hash it first so it can be found */ insert_dquot_hash(dquot); + dqstats.lookups++; + spin_unlock(&dq_list_lock); read_dqblk(dquot); } else { - if (!dquot->dq_count) + if (!atomic_read(&dquot->dq_count)) remove_free_dquot(dquot); - get_dquot_ref(dquot); + atomic_inc(&dquot->dq_count); dqstats.cache_hits++; + dqstats.lookups++; + spin_unlock(&dq_list_lock); wait_on_dquot(dquot); if (empty) - dqput(empty); + kmem_cache_free(dquot_cachep, empty); } - if (!dquot->dq_sb) { /* Has somebody invalidated entry under us? */ - printk(KERN_ERR "VFS: dqget(): Quota invalidated in dqget()!\n"); - dqput(dquot); - return NODQUOT; - } - ++dquot->dq_referenced; - dqstats.lookups++; - - return dquot; -} - -/* Duplicate reference to dquot got from inode */ -static struct dquot *dqduplicate(struct dquot *dquot) -{ - if (dquot == NODQUOT) - return NODQUOT; - get_dquot_ref(dquot); - if (!dquot->dq_sb) { - printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n"); - put_dquot_ref(dquot); - return NODQUOT; - } - if (dquot->dq_flags & DQ_LOCKED) - printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n"); - get_dquot_dup_ref(dquot); - dquot->dq_referenced++; - dqstats.lookups++; +#ifdef __DQUOT_PARANOIA + if (!dquot->dq_sb) /* Has somebody invalidated entry under us? */ + BUG(); +#endif return dquot; } -/* Put duplicated reference */ -static void dqputduplicate(struct dquot *dquot) -{ - if (!dquot->dq_dup_ref) { - printk(KERN_ERR "VFS: dqputduplicate(): Duplicated dquot put without duplicate reference.\n"); - return; - } - put_dquot_dup_ref(dquot); - if (!dquot->dq_dup_ref) - wake_up(&dquot->dq_wait_free); - put_dquot_ref(dquot); - dqstats.drops++; -} - static int dqinit_needed(struct inode *inode, int type) { int cnt; @@ -657,6 +553,7 @@ static int dqinit_needed(struct inode *inode, int type) return 0; } +/* This routine is guarded by dqoff_sem semaphore */ static void add_dquot_ref(struct super_block *sb, int type) { struct list_head *p; @@ -683,14 +580,13 @@ restart: /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ static inline int dqput_blocks(struct dquot *dquot) { - if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) - return 1; - if (dquot->dq_count <= 1 && dquot->dq_flags & DQ_MOD) + if (atomic_read(&dquot->dq_count) <= 1 && dquot_dirty(dquot)) return 1; return 0; } /* Remove references to dquots from inode - add dquot to list for freeing if needed */ +/* We can't race with anybody because we hold dqoff_sem for writing... */ int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { struct dquot *dquot = inode->i_dquot[type]; @@ -706,9 +602,13 @@ int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofr put_it: if (dquot != NODQUOT) { if (dqput_blocks(dquot)) { - if (dquot->dq_count != 1) - printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count); +#ifdef __DQUOT_PARANOIA + if (atomic_read(&dquot->dq_count) != 1) + printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count)); +#endif + spin_lock(&dq_list_lock); list_add(&dquot->dq_free, tofree_head); /* As dquot must have currently users it can't be on the free list... */ + spin_unlock(&dq_list_lock); return 1; } else @@ -718,12 +618,12 @@ put_it: } /* Free list of dquots - called from inode.c */ +/* dquots are removed from inodes, no new references can be got so we are the only ones holding reference */ void put_dquot_list(struct list_head *tofree_head) { struct list_head *act_head; struct dquot *dquot; - lock_kernel(); act_head = tofree_head->next; /* So now we have dquots on the list... Just free them */ while (act_head != tofree_head) { @@ -732,7 +632,6 @@ void put_dquot_list(struct list_head *tofree_head) list_del_init(&dquot->dq_free); /* Remove dquot from the list so we won't have problems... */ dqput(dquot); } - unlock_kernel(); } static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) @@ -755,7 +654,7 @@ static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number) dquot->dq_dqb.dqb_curinodes = 0; if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit) dquot->dq_dqb.dqb_itime = (time_t) 0; - dquot->dq_flags &= ~DQ_INODES; + clear_bit(DQ_INODES_B, &dquot->dq_flags); mark_dquot_dirty(dquot); } @@ -767,17 +666,17 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) dquot->dq_dqb.dqb_curspace = 0; if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit) dquot->dq_dqb.dqb_btime = (time_t) 0; - dquot->dq_flags &= ~DQ_BLKS; + clear_bit(DQ_BLKS_B, &dquot->dq_flags); mark_dquot_dirty(dquot); } -static inline int need_print_warning(struct dquot *dquot, int flag) +static inline int need_print_warning(struct dquot *dquot) { switch (dquot->dq_type) { case USRQUOTA: - return current->fsuid == dquot->dq_id && !(dquot->dq_flags & flag); + return current->fsuid == dquot->dq_id; case GRPQUOTA: - return in_group_p(dquot->dq_id) && !(dquot->dq_flags & flag); + return in_group_p(dquot->dq_id); } return 0; } @@ -795,12 +694,11 @@ static inline int need_print_warning(struct dquot *dquot, int flag) static void print_warning(struct dquot *dquot, const char warntype) { char *msg = NULL; - int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS : - ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES : 0); + int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B : + ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0); - if (!need_print_warning(dquot, flag)) + if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) return; - dquot->dq_flags |= flag; tty_write_message(current->tty, dquot->dq_sb->s_id); if (warntype == ISOFTWARN || warntype == BSOFTWARN) tty_write_message(current->tty, ": warning, "); @@ -847,10 +745,11 @@ static inline char ignore_hardlimit(struct dquot *dquot) (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); } +/* needs dq_data_lock */ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) { *warntype = NOWARN; - if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) + if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; if (dquot->dq_dqb.dqb_ihardlimit && @@ -878,10 +777,11 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) return QUOTA_OK; } +/* needs dq_data_lock */ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) { *warntype = 0; - if (space <= 0 || dquot->dq_flags & DQ_FAKE) + if (space <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) return QUOTA_OK; if (dquot->dq_dqb.dqb_bhardlimit && @@ -926,19 +826,19 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war */ void dquot_initialize(struct inode *inode, int type) { - struct dquot *dquot[MAXQUOTAS]; unsigned int id = 0; int cnt; - if (IS_NOQUOTA(inode)) + down_write(&sb_dqopt(inode->i_sb)->dqoff_sem); + /* Having dqoff lock we know NOQUOTA flags can't be altered... */ + if (IS_NOQUOTA(inode)) { + up_write(&sb_dqopt(inode->i_sb)->dqoff_sem); return; - /* Build list of quotas to initialize... We can block here */ + } + /* Build list of quotas to initialize... */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = NODQUOT; if (type != -1 && cnt != type) continue; - if (!sb_has_quota_enabled(inode->i_sb, cnt)) - continue; if (inode->i_dquot[cnt] == NODQUOT) { switch (cnt) { case USRQUOTA: @@ -948,22 +848,12 @@ void dquot_initialize(struct inode *inode, int type) id = inode->i_gid; break; } - dquot[cnt] = dqget(inode->i_sb, id, cnt); + inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt); + if (inode->i_dquot[cnt]) + inode->i_flags |= S_QUOTA; } } - /* NOBLOCK START: Here we shouldn't block */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (dquot[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt) || inode->i_dquot[cnt] != NODQUOT) - continue; - inode->i_dquot[cnt] = dquot[cnt]; - dquot[cnt] = NODQUOT; - inode->i_flags |= S_QUOTA; - } - /* NOBLOCK END */ - /* Put quotas which we didn't use */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (dquot[cnt] != NODQUOT) - dqput(dquot[cnt]); + up_write(&sb_dqopt(inode->i_sb)->dqoff_sem); } /* @@ -971,57 +861,56 @@ void dquot_initialize(struct inode *inode, int type) * * Note: this is a blocking operation. */ -void dquot_drop(struct inode *inode) +static void dquot_drop_nolock(struct inode *inode) { - struct dquot *dquot; int cnt; inode->i_flags &= ~S_QUOTA; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] == NODQUOT) continue; - dquot = inode->i_dquot[cnt]; + dqput(inode->i_dquot[cnt]); inode->i_dquot[cnt] = NODQUOT; - dqput(dquot); } } +void dquot_drop(struct inode *inode) +{ + down_write(&sb_dqopt(inode->i_sb)->dqoff_sem); + dquot_drop_nolock(inode); + up_write(&sb_dqopt(inode->i_sb)->dqoff_sem); +} + /* * This operation can block, but only after everything is updated */ int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) { int cnt, ret = NO_QUOTA; - struct dquot *dquot[MAXQUOTAS]; char warntype[MAXQUOTAS]; - lock_kernel(); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = NODQUOT; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - } - /* NOBLOCK Start */ + + down_read(&sb_dqopt(inode->i_sb)->dqoff_sem); + spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = dqduplicate(inode->i_dquot[cnt]); - if (dquot[cnt] == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - if (check_bdq(dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA) + if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) == NO_QUOTA) goto warn_put_all; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (dquot[cnt] == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - dquot_incr_space(dquot[cnt], number); + dquot_incr_space(inode->i_dquot[cnt], number); } inode_add_bytes(inode, number); - /* NOBLOCK End */ ret = QUOTA_OK; warn_put_all: - flush_warnings(dquot, warntype); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (dquot[cnt] != NODQUOT) - dqputduplicate(dquot[cnt]); - unlock_kernel(); + spin_unlock(&dq_data_lock); + flush_warnings(inode->i_dquot, warntype); + up_read(&sb_dqopt(inode->i_sb)->dqoff_sem); return ret; } @@ -1031,36 +920,29 @@ warn_put_all: int dquot_alloc_inode(const struct inode *inode, unsigned long number) { int cnt, ret = NO_QUOTA; - struct dquot *dquot[MAXQUOTAS]; char warntype[MAXQUOTAS]; - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = NODQUOT; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - } - /* NOBLOCK Start */ - lock_kernel(); + down_read(&sb_dqopt(inode->i_sb)->dqoff_sem); + spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot[cnt] = dqduplicate(inode -> i_dquot[cnt]); - if (dquot[cnt] == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - if (check_idq(dquot[cnt], number, warntype+cnt) == NO_QUOTA) + if (check_idq(inode->i_dquot[cnt], number, warntype+cnt) == NO_QUOTA) goto warn_put_all; } for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (dquot[cnt] == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - dquot_incr_inodes(dquot[cnt], number); + dquot_incr_inodes(inode->i_dquot[cnt], number); } - /* NOBLOCK End */ ret = QUOTA_OK; warn_put_all: - flush_warnings(dquot, warntype); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (dquot[cnt] != NODQUOT) - dqputduplicate(dquot[cnt]); - unlock_kernel(); + spin_unlock(&dq_data_lock); + flush_warnings((struct dquot **)inode->i_dquot, warntype); + up_read(&sb_dqopt(inode->i_sb)->dqoff_sem); return ret; } @@ -1070,20 +952,17 @@ warn_put_all: void dquot_free_space(struct inode *inode, qsize_t number) { unsigned int cnt; - struct dquot *dquot; - /* NOBLOCK Start */ - lock_kernel(); + down_read(&sb_dqopt(inode->i_sb)->dqoff_sem); + spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot = dqduplicate(inode->i_dquot[cnt]); - if (dquot == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - dquot_decr_space(dquot, number); - dqputduplicate(dquot); + dquot_decr_space(inode->i_dquot[cnt], number); } inode_sub_bytes(inode, number); - unlock_kernel(); - /* NOBLOCK End */ + spin_unlock(&dq_data_lock); + up_read(&sb_dqopt(inode->i_sb)->dqoff_sem); } /* @@ -1092,19 +971,16 @@ void dquot_free_space(struct inode *inode, qsize_t number) void dquot_free_inode(const struct inode *inode, unsigned long number) { unsigned int cnt; - struct dquot *dquot; - /* NOBLOCK Start */ - lock_kernel(); + down_read(&sb_dqopt(inode->i_sb)->dqoff_sem); + spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - dquot = dqduplicate(inode->i_dquot[cnt]); - if (dquot == NODQUOT) + if (inode->i_dquot[cnt] == NODQUOT) continue; - dquot_decr_inodes(dquot, number); - dqputduplicate(dquot); + dquot_decr_inodes(inode->i_dquot[cnt], number); } - unlock_kernel(); - /* NOBLOCK End */ + spin_unlock(&dq_data_lock); + up_read(&sb_dqopt(inode->i_sb)->dqoff_sem); } /* @@ -1126,10 +1002,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) transfer_to[cnt] = transfer_from[cnt] = NODQUOT; warntype[cnt] = NOWARN; } + down_write(&sb_dqopt(inode->i_sb)->dqoff_sem); + if (IS_NOQUOTA(inode)) /* File without quota accounting? */ + goto warn_put_all; /* First build the transfer_to list - here we can block on reading of dquots... */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (!sb_has_quota_enabled(inode->i_sb, cnt)) - continue; switch (cnt) { case USRQUOTA: if (!chuid) @@ -1143,16 +1020,13 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) break; } } - /* NOBLOCK START: From now on we shouldn't block */ + spin_lock(&dq_data_lock); space = inode_get_bytes(inode); /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - /* The second test can fail when quotaoff is in progress... */ - if (transfer_to[cnt] == NODQUOT || !sb_has_quota_enabled(inode->i_sb, cnt)) - continue; - transfer_from[cnt] = dqduplicate(inode->i_dquot[cnt]); - if (transfer_from[cnt] == NODQUOT) /* Can happen on quotafiles (quota isn't initialized on them)... */ + if (transfer_to[cnt] == NODQUOT) continue; + transfer_from[cnt] = inode->i_dquot[cnt]; if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA || check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA) goto warn_put_all; @@ -1163,9 +1037,9 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* - * Skip changes for same uid or gid or for non-existing quota-type. + * Skip changes for same uid or gid or for turned off quota-type. */ - if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT) + if (transfer_to[cnt] == NODQUOT) continue; dquot_decr_inodes(transfer_from[cnt], 1); @@ -1174,26 +1048,17 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) dquot_incr_inodes(transfer_to[cnt], 1); dquot_incr_space(transfer_to[cnt], space); - if (inode->i_dquot[cnt] == NODQUOT) - BUG(); inode->i_dquot[cnt] = transfer_to[cnt]; - /* - * We've got to release transfer_from[] twice - once for dquot_transfer() and - * once for inode. We don't want to release transfer_to[] as it's now placed in inode - */ - transfer_to[cnt] = transfer_from[cnt]; } - /* NOBLOCK END. From now on we can block as we wish */ ret = QUOTA_OK; warn_put_all: + spin_unlock(&dq_data_lock); flush_warnings(transfer_to, warntype); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - /* First we must put duplicate - otherwise we might deadlock */ - if (transfer_to[cnt] != NODQUOT) - dqputduplicate(transfer_to[cnt]); + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (transfer_from[cnt] != NODQUOT) dqput(transfer_from[cnt]); - } + up_write(&sb_dqopt(inode->i_sb)->dqoff_sem); return ret; } @@ -1245,24 +1110,30 @@ int vfs_quota_off(struct super_block *sb, int type) int cnt; struct quota_info *dqopt = sb_dqopt(sb); - lock_kernel(); if (!sb) goto out; /* We need to serialize quota_off() for device */ - down(&dqopt->dqoff_sem); + down_write(&dqopt->dqoff_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; - if (!is_enabled(dqopt, cnt)) + if (!sb_has_quota_enabled(sb, cnt)) continue; reset_enable_flags(dqopt, cnt); /* Note: these are blocking operations */ remove_dquot_ref(sb, cnt); invalidate_dquots(sb, cnt); - if (info_dirty(&dqopt->info[cnt])) + /* + * Now all dquots should be invalidated, all writes done so we should be only + * users of the info. No locks needed. + */ + if (info_dirty(&dqopt->info[cnt])) { + down(&dqopt->dqio_sem); dqopt->ops[cnt]->write_file_info(sb, cnt); + up(&dqopt->dqio_sem); + } if (dqopt->ops[cnt]->free_file_info) dqopt->ops[cnt]->free_file_info(sb, cnt); put_quota_format(dqopt->info[cnt].dqi_format); @@ -1274,15 +1145,14 @@ int vfs_quota_off(struct super_block *sb, int type) dqopt->info[cnt].dqi_bgrace = 0; dqopt->ops[cnt] = NULL; } - up(&dqopt->dqoff_sem); + up_write(&dqopt->dqoff_sem); out: - unlock_kernel(); return 0; } int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) { - struct file *f = NULL; + struct file *f; struct inode *inode; struct quota_info *dqopt = sb_dqopt(sb); struct quota_format_type *fmt = find_quota_format(format_id); @@ -1290,19 +1160,11 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) if (!fmt) return -ESRCH; - if (is_enabled(dqopt, type)) { - error = -EBUSY; + f = filp_open(path, O_RDWR, 0600); + if (IS_ERR(f)) { + error = PTR_ERR(f); goto out_fmt; } - - down(&dqopt->dqoff_sem); - - f = filp_open(path, O_RDWR, 0600); - - error = PTR_ERR(f); - if (IS_ERR(f)) - goto out_lock; - dqopt->files[type] = f; error = -EIO; if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; @@ -1313,30 +1175,41 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) error = -EACCES; if (!S_ISREG(inode->i_mode)) goto out_f; + + down_write(&dqopt->dqoff_sem); + if (sb_has_quota_enabled(sb, type)) { + error = -EBUSY; + goto out_lock; + } + dqopt->files[type] = f; error = -EINVAL; if (!fmt->qf_ops->check_quota_file(sb, type)) - goto out_f; + goto out_lock; /* We don't want quota on quota files */ - dquot_drop(inode); + dquot_drop_nolock(inode); inode->i_flags |= S_NOQUOTA; dqopt->ops[type] = fmt->qf_ops; dqopt->info[type].dqi_format = fmt; - if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) - goto out_f; + down(&dqopt->dqio_sem); + if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { + up(&dqopt->dqio_sem); + goto out_lock; + } + up(&dqopt->dqio_sem); set_enable_flags(dqopt, type); add_dquot_ref(sb, type); - up(&dqopt->dqoff_sem); + up_write(&dqopt->dqoff_sem); return 0; -out_f: - if (f) - filp_close(f, NULL); - dqopt->files[type] = NULL; out_lock: - up(&dqopt->dqoff_sem); + inode->i_flags &= ~S_NOQUOTA; + dqopt->files[type] = NULL; + up_write(&dqopt->dqoff_sem); +out_f: + filp_close(f, NULL); out_fmt: put_quota_format(fmt); @@ -1348,6 +1221,7 @@ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) { struct mem_dqblk *dm = &dquot->dq_dqb; + spin_lock(&dq_data_lock); di->dqb_bhardlimit = dm->dqb_bhardlimit; di->dqb_bsoftlimit = dm->dqb_bsoftlimit; di->dqb_curspace = dm->dqb_curspace; @@ -1357,16 +1231,21 @@ static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) di->dqb_btime = dm->dqb_btime; di->dqb_itime = dm->dqb_itime; di->dqb_valid = QIF_ALL; + spin_unlock(&dq_data_lock); } int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) { - struct dquot *dquot = dqget(sb, id, type); + struct dquot *dquot; - if (!dquot) - return -EINVAL; + down_read(&sb_dqopt(sb)->dqoff_sem); + if (!(dquot = dqget(sb, id, type))) { + up_read(&sb_dqopt(sb)->dqoff_sem); + return -ESRCH; + } do_get_dqblk(dquot, di); dqput(dquot); + up_read(&sb_dqopt(sb)->dqoff_sem); return 0; } @@ -1376,6 +1255,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) struct mem_dqblk *dm = &dquot->dq_dqb; int check_blim = 0, check_ilim = 0; + spin_lock(&dq_data_lock); if (di->dqb_valid & QIF_SPACE) { dm->dqb_curspace = di->dqb_curspace; check_blim = 1; @@ -1402,7 +1282,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) if (check_blim) { if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) { dm->dqb_btime = 0; - dquot->dq_flags &= ~DQ_BLKS; + clear_bit(DQ_BLKS_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; @@ -1410,46 +1290,67 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) if (check_ilim) { if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { dm->dqb_itime = 0; - dquot->dq_flags &= ~DQ_INODES; + clear_bit(DQ_INODES_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; } if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) - dquot->dq_flags &= ~DQ_FAKE; + clear_bit(DQ_FAKE_B, &dquot->dq_flags); else - dquot->dq_flags |= DQ_FAKE; - dquot->dq_flags |= DQ_MOD; + set_bit(DQ_FAKE_B, &dquot->dq_flags); + mark_dquot_dirty(dquot); + spin_unlock(&dq_data_lock); } int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) { - struct dquot *dquot = dqget(sb, id, type); + struct dquot *dquot; - if (!dquot) - return -EINVAL; + down_read(&sb_dqopt(sb)->dqoff_sem); + if (!(dquot = dqget(sb, id, type))) { + up_read(&sb_dqopt(sb)->dqoff_sem); + return -ESRCH; + } do_set_dqblk(dquot, di); dqput(dquot); + up_read(&sb_dqopt(sb)->dqoff_sem); return 0; } /* Generic routine for getting common part of quota file information */ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) { - struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; - + struct mem_dqinfo *mi; + + down_read(&sb_dqopt(sb)->dqoff_sem); + if (!sb_has_quota_enabled(sb, type)) { + up_read(&sb_dqopt(sb)->dqoff_sem); + return -ESRCH; + } + mi = sb_dqopt(sb)->info + type; + spin_lock(&dq_data_lock); ii->dqi_bgrace = mi->dqi_bgrace; ii->dqi_igrace = mi->dqi_igrace; ii->dqi_flags = mi->dqi_flags & DQF_MASK; ii->dqi_valid = IIF_ALL; + spin_unlock(&dq_data_lock); + up_read(&sb_dqopt(sb)->dqoff_sem); return 0; } /* Generic routine for setting common part of quota file information */ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) { - struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; + struct mem_dqinfo *mi; + down_read(&sb_dqopt(sb)->dqoff_sem); + if (!sb_has_quota_enabled(sb, type)) { + up_read(&sb_dqopt(sb)->dqoff_sem); + return -ESRCH; + } + mi = sb_dqopt(sb)->info + type; + spin_lock(&dq_data_lock); if (ii->dqi_valid & IIF_BGRACE) mi->dqi_bgrace = ii->dqi_bgrace; if (ii->dqi_valid & IIF_IGRACE) @@ -1457,6 +1358,8 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) if (ii->dqi_valid & IIF_FLAGS) mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); mark_info_dirty(mi); + spin_unlock(&dq_data_lock); + up_read(&sb_dqopt(sb)->dqoff_sem); return 0; } @@ -1502,7 +1405,7 @@ static int __init dquot_init(void) register_sysctl_table(sys_table, 0); for (i = 0; i < NR_DQHASH; i++) INIT_LIST_HEAD(dquot_hash + i); - printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__); + printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); dquot_cachep = kmem_cache_create("dquot", sizeof(struct dquot), sizeof(unsigned long) * 4, @@ -1519,3 +1422,5 @@ module_init(dquot_init); EXPORT_SYMBOL(register_quota_format); EXPORT_SYMBOL(unregister_quota_format); EXPORT_SYMBOL(dqstats); +EXPORT_SYMBOL(dq_list_lock); +EXPORT_SYMBOL(dq_data_lock); diff --git a/fs/efs/super.c b/fs/efs/super.c index ffd46cf63bc5..f0ece23a28c3 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -13,6 +13,7 @@ #include <linux/efs_fs_sb.h> #include <linux/slab.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> static struct super_block *efs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 23116c16e3ce..55bbb5595337 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -25,6 +25,7 @@ #include <linux/random.h> #include <linux/buffer_head.h> #include <linux/smp_lock.h> +#include <linux/vfs.h> #include <asm/uaccess.h> #include "ext2.h" #include "xattr.h" diff --git a/fs/ext3/super.c b/fs/ext3/super.c index c34781e47df3..3aeb04a1159c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -29,6 +29,7 @@ #include <linux/blkdev.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/uaccess.h> #include "xattr.h" #include "acl.h" diff --git a/fs/fat/inode.c b/fs/fat/inode.c index f0e05a3c04e0..ebac66df836f 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -19,6 +19,7 @@ #include <linux/pagemap.h> #include <linux/buffer_head.h> #include <linux/mount.h> +#include <linux/vfs.h> #include <asm/unaligned.h> /* diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 7b9060cba753..9733ee2d1d6a 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -41,6 +41,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/vfs.h> #include "vxfs.h" #include "vxfs_extern.h" diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 62f335e8abb1..89195405b3d2 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/vfs.h> MODULE_LICENSE("GPL"); diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 230b622915a6..84d5023cac6c 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -162,6 +162,8 @@ static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n) return 0; } +struct statfs; + /* alloc.c */ int hpfs_chk_sectors(struct super_block *, secno, int, char *); diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index be1715fa4be4..79a57406e602 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -11,6 +11,7 @@ #include "hpfs_fn.h" #include <linux/module.h> #include <linux/init.h> +#include <linux/vfs.h> /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ diff --git a/fs/inode.c b/fs/inode.c index 5fba39ebe82d..1c36522999c3 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1133,9 +1133,8 @@ void remove_dquot_ref(struct super_block *sb, int type) if (!sb->dq_op) return; /* nothing to do */ - /* We have to be protected against other CPUs */ - lock_kernel(); /* This lock is for quota code */ spin_lock(&inode_lock); /* This lock is for inodes code */ + /* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */ list_for_each(act_head, &inode_in_use) { inode = list_entry(act_head, struct inode, i_list); @@ -1158,7 +1157,6 @@ void remove_dquot_ref(struct super_block *sb, int type) remove_inode_dquot_ref(inode, type, &tofree_head); } spin_unlock(&inode_lock); - unlock_kernel(); put_dquot_list(&tofree_head); } diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index a0fa6fa9c472..54cff6f1b0df 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -28,7 +28,7 @@ #include <linux/smp_lock.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> - +#include <linux/vfs.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 325afb2d489e..ed95aceaa941 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -48,6 +48,7 @@ #include <linux/blkdev.h> #include <linux/quotaops.h> #include <linux/highmem.h> +#include <linux/vfs.h> #include <asm/semaphore.h> #include <asm/byteorder.h> #include <asm/uaccess.h> diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 2fed2c33e36d..b785d9a36055 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -20,6 +20,7 @@ #include <linux/mtd/mtd.h> #include <linux/pagemap.h> #include <linux/slab.h> +#include <linux/vfs.h> #include "nodelist.h" int jffs2_statfs(struct super_block *sb, struct statfs *buf) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index e7b599b95220..b1654cff562b 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -96,6 +96,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) #define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf)) +struct statfs; /* wbuf.c */ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 938937f33b7b..cc2731f0ca6d 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -21,7 +21,9 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/completion.h> +#include <linux/vfs.h> #include <asm/uaccess.h> + #include "jfs_incore.h" #include "jfs_filsys.h" #include "jfs_metapage.h" diff --git a/fs/libfs.c b/fs/libfs.c index e3d30987c919..16325e7baf90 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -4,7 +4,7 @@ */ #include <linux/pagemap.h> -#include <linux/smp_lock.h> +#include <linux/vfs.h> int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index c327d5f03443..a58cf733da35 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/highuid.h> +#include <linux/vfs.h> static void minix_read_inode(struct inode * inode); static void minix_write_inode(struct inode * inode, int wait); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index ca32f9246891..3a72623c1aba 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -28,6 +28,7 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/vfs.h> #include <linux/ncp_fs.h> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 207401451f9f..e77e6eab9cc5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -33,6 +33,7 @@ #include <linux/smp_lock.h> #include <linux/seq_file.h> #include <linux/mount.h> +#include <linux/vfs.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 7a9500315bd3..3cb91cc3cb03 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -14,7 +14,7 @@ #include <linux/dcache.h> #include <linux/namei.h> #include <linux/mm.h> - +#include <linux/vfs.h> #include <linux/sunrpc/xdr.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d490011652e1..906b727f8873 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -48,7 +48,7 @@ #include <linux/compatmac.h> #include <linux/fs.h> #include <linux/namei.h> - +#include <linux/vfs.h> #include <linux/sunrpc/xdr.h> #include <linux/sunrpc/svc.h> #include <linux/sunrpc/clnt.h> diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 2a3f9e1638c1..8cfe59c30295 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -9,7 +9,7 @@ #include <linux/types.h> #include <linux/time.h> #include <linux/nfs.h> - +#include <linux/vfs.h> #include <linux/sunrpc/xdr.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 820e8de68827..aaec5a01e7fa 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -34,7 +34,7 @@ #include <linux/in.h> #include <linux/module.h> #include <linux/namei.h> - +#include <linux/vfs.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> #ifdef CONFIG_NFSD_V3 diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index b93891c2873f..55a092114ecd 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -27,6 +27,7 @@ #include <linux/blkdev.h> /* For bdev_hardsect_size(). */ #include <linux/backing-dev.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include "ntfs.h" #include "sysctl.h" diff --git a/fs/open.c b/fs/open.c index 677a181c28f5..edebacf1148e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -18,7 +18,7 @@ #include <linux/backing-dev.h> #include <linux/security.h> #include <linux/mount.h> - +#include <linux/vfs.h> #include <asm/uaccess.h> #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 616e97433632..9da0bfe9a348 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -25,7 +25,7 @@ #include <linux/smp_lock.h> #include <linux/pagemap.h> #include <linux/buffer_head.h> - +#include <linux/vfs.h> #include <asm/uaccess.h> #define QNX4_VERSION 4 diff --git a/fs/quota.c b/fs/quota.c index 600765da6ecb..54302d445086 100644 --- a/fs/quota.c +++ b/fs/quota.c @@ -84,6 +84,7 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t case Q_SETINFO: case Q_SETQUOTA: case Q_GETQUOTA: + /* This is just informative test so we are satisfied without a lock */ if (!sb_has_quota_enabled(sb, type)) return -ESRCH; } @@ -151,7 +152,13 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, cadd case Q_GETFMT: { __u32 fmt; + down_read(&sb_dqopt(sb)->dqoff_sem); + if (!sb_has_quota_enabled(sb, type)) { + up_read(&sb_dqopt(sb)->dqoff_sem); + return -ESRCH; + } fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; + up_read(&sb_dqopt(sb)->dqoff_sem); if (copy_to_user(addr, &fmt, sizeof(fmt))) return -EFAULT; return 0; @@ -244,7 +251,6 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, ca struct super_block *sb = NULL; int ret = -EINVAL; - lock_kernel(); cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; @@ -259,6 +265,5 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, ca out: if (sb) drop_super(sb); - unlock_kernel(); return ret; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5ff239899835..69e5fc60866e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #define REISERFS_OLD_BLOCKSIZE 4096 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 58392f3beb2d..d0c335625c14 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -24,7 +24,7 @@ #include <linux/seq_file.h> #include <linux/mount.h> #include <linux/net.h> - +#include <linux/vfs.h> #include <linux/smb_fs.h> #include <linux/smbno.h> #include <linux/smb_mount.h> diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index cd495b55b0aa..b23f9e1bfa68 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -19,7 +19,7 @@ #include <linux/nls.h> #include <linux/smp_lock.h> #include <linux/net.h> - +#include <linux/vfs.h> #include <linux/smb_fs.h> #include <linux/smbno.h> #include <linux/smb_mount.h> diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index 56430b8e2935..07b690eb8848 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -4,6 +4,7 @@ struct smb_request; struct sock; +struct statfs; /* proc.c */ extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); diff --git a/fs/super.c b/fs/super.c index 4242b0c46fd1..09e0fa12b126 100644 --- a/fs/super.c +++ b/fs/super.c @@ -30,6 +30,7 @@ #include <linux/buffer_head.h> /* for fsync_super() */ #include <linux/mount.h> #include <linux/security.h> +#include <linux/vfs.h> #include <asm/uaccess.h> @@ -70,7 +71,7 @@ static struct super_block *alloc_super(void) atomic_set(&s->s_active, 1); sema_init(&s->s_vfs_rename_sem,1); sema_init(&s->s_dquot.dqio_sem, 1); - sema_init(&s->s_dquot.dqoff_sem, 1); + init_rwsem(&s->s_dquot.dqoff_sem); s->s_maxbytes = MAX_NON_LFS; s->dq_op = sb_dquot_ops; s->s_qcop = sb_quotactl_ops; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 915883148aa1..23bc0fc34ec6 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/byteorder.h> #include "sysv.h" diff --git a/fs/udf/super.c b/fs/udf/super.c index a602beb96b53..6fafb04f6a99 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -56,6 +56,7 @@ #include <linux/nls.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include <asm/byteorder.h> #include <linux/udf_fs.h> diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 48f3d53ead3d..39282f551371 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -81,6 +81,7 @@ #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/vfs.h> #include "swab.h" #include "util.h" diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h index 3920a9cf575f..efcff94b19dd 100644 --- a/fs/xfs/linux/xfs_linux.h +++ b/fs/xfs/linux/xfs_linux.h @@ -42,6 +42,7 @@ #include <linux/sched.h> #include <linux/bitops.h> #include <linux/major.h> +#include <linux/vfs.h> #include <asm/page.h> #include <asm/div64.h> diff --git a/include/asm-ppc/module.h b/include/asm-ppc/module.h index 7d75a3e3e2ee..9686cfa4fc36 100644 --- a/include/asm-ppc/module.h +++ b/include/asm-ppc/module.h @@ -18,16 +18,17 @@ struct ppc_plt_entry struct mod_arch_specific { - /* How much of the core is actually taken up with core (then - we know the rest is for the PLT */ - unsigned int core_plt_offset; - - /* Same for init */ - unsigned int init_plt_offset; + /* Indices of PLT sections within module. */ + unsigned int core_plt_section, init_plt_section; }; #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Ehdr Elf32_Ehdr +/* Make empty sections for module_frob_arch_sections to expand. */ +#ifdef MODULE +asm(".section .plt,\"aws\",@nobits; .align 3; .previous"); +asm(".section .plt.init,\"aws\",@nobits; .align 3; .previous"); +#endif #endif /* _ASM_PPC_MODULE_H */ diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index 0e3f73f7a73e..5c3fefddd4f7 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -6,6 +6,8 @@ #define CODA_SUPER_MAGIC 0x73757245 +struct statfs; + struct coda_sb_info { struct venus_comm * sbi_vcomm; diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h index 15c85cccdded..491dc297b930 100644 --- a/include/linux/devfs_fs_kernel.h +++ b/include/linux/devfs_fs_kernel.h @@ -53,17 +53,8 @@ extern int devfs_mk_symlink (devfs_handle_t dir, const char *name, devfs_handle_t *handle, void *info); extern devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info); -extern devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name, - int traverse_symlinks); -extern devfs_handle_t devfs_get_handle_from_inode (struct inode *inode); extern int devfs_generate_path (devfs_handle_t de, char *path, int buflen); extern int devfs_set_file_size (devfs_handle_t de, unsigned long size); -extern void *devfs_get_info (devfs_handle_t de); -extern int devfs_set_info (devfs_handle_t de, void *info); -extern devfs_handle_t devfs_get_parent (devfs_handle_t de); -extern devfs_handle_t devfs_get_first_child (devfs_handle_t de); -extern devfs_handle_t devfs_get_next_sibling (devfs_handle_t de); -extern const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen); extern int devfs_only (void); extern int devfs_register_tape (devfs_handle_t de); extern void devfs_unregister_tape(int num); @@ -115,19 +106,9 @@ static inline devfs_handle_t devfs_mk_dir (devfs_handle_t dir, { return NULL; } -static inline devfs_handle_t devfs_get_handle (devfs_handle_t dir, - const char *name, - int traverse_symlinks) -{ - return NULL; -} static inline void devfs_remove(const char *fmt, ...) { } -static inline devfs_handle_t devfs_get_handle_from_inode (struct inode *inode) -{ - return NULL; -} static inline int devfs_generate_path (devfs_handle_t de, char *path, int buflen) { @@ -137,31 +118,6 @@ static inline int devfs_set_file_size (devfs_handle_t de, unsigned long size) { return -ENOSYS; } -static inline void *devfs_get_info (devfs_handle_t de) -{ - return NULL; -} -static inline int devfs_set_info (devfs_handle_t de, void *info) -{ - return 0; -} -static inline devfs_handle_t devfs_get_parent (devfs_handle_t de) -{ - return NULL; -} -static inline devfs_handle_t devfs_get_first_child (devfs_handle_t de) -{ - return NULL; -} -static inline devfs_handle_t devfs_get_next_sibling (devfs_handle_t de) -{ - return NULL; -} -static inline const char *devfs_get_name (devfs_handle_t de, - unsigned int *namelen) -{ - return NULL; -} static inline int devfs_only (void) { return 0; diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h index a636043ab8a3..31096307c124 100644 --- a/include/linux/efs_fs.h +++ b/include/linux/efs_fs.h @@ -49,6 +49,8 @@ static inline struct efs_sb_info *SUPER_INFO(struct super_block *sb) return sb->s_fs_info; } +struct statfs; + extern struct inode_operations efs_dir_inode_operations; extern struct file_operations efs_dir_operations; extern struct address_space_operations efs_symlink_aops; diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 634459be7d64..f909a967778e 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -20,6 +20,9 @@ #include <linux/ext3_fs_i.h> #include <linux/ext3_fs_sb.h> + +struct statfs; + /* * The second extended filesystem constants/structures */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 3fa13b80747d..878f2d2e4a9f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -11,7 +11,6 @@ #include <linux/limits.h> #include <linux/wait.h> #include <linux/types.h> -#include <linux/vfs.h> #include <linux/kdev_t.h> #include <linux/ioctl.h> #include <linux/list.h> @@ -25,6 +24,7 @@ struct iovec; struct nameidata; struct pipe_inode_info; struct poll_table_struct; +struct statfs; struct vm_area_struct; struct vfsmount; diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index 928ae553ca37..5001ff39204d 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -15,20 +15,11 @@ unsigned long find_symbol_internal(Elf_Shdr *sechdrs, /* These must be implemented by the specific architecture */ -/* Total size to allocate for the non-releasable code; return len or - -error. mod->core_size is the current generic tally. */ -long module_core_size(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, - struct module *mod); - -/* Total size of (if any) sections to be freed after init. Return 0 - for none, len, or -error. mod->init_size is the current generic - tally. */ -long module_init_size(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, - struct module *mod); +/* Adjust arch-specific sections. Return 0 on success. */ +int module_frob_arch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod); /* Allocator used for allocating struct module, core sections and init sections. Returns NULL on failure. */ diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 1cb5e7d2b3d7..2945cb406b64 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -8,6 +8,9 @@ #include <linux/string.h> #include <asm/byteorder.h> +struct statfs; + + #define SECTOR_SIZE 512 /* sector size (bytes) */ #define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */ #define MSDOS_DPB (MSDOS_DPS) /* dir entries per block */ diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index b00141bc86e5..970474550bb9 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -8,6 +8,7 @@ #define LINUX_NFSD_H #include <linux/fs.h> +#include <linux/vfs.h> #include <linux/nfs.h> struct nfsd_fhandle { diff --git a/include/linux/quota.h b/include/linux/quota.h index 02bf7c53a6d4..e5b1e2187156 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -37,6 +37,7 @@ #include <linux/errno.h> #include <linux/types.h> +#include <linux/spinlock.h> #define __DQUOT_VERSION__ "dquot_6.5.1" #define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 @@ -44,6 +45,9 @@ typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ typedef __u64 qsize_t; /* Type in which we store sizes */ +extern spinlock_t dq_list_lock; +extern spinlock_t dq_data_lock; + /* Size of blocks in which are counted size limits */ #define QUOTABLOCK_BITS 10 #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) @@ -155,7 +159,7 @@ struct quota_format_type; struct mem_dqinfo { struct quota_format_type *dqi_format; - int dqi_flags; + unsigned long dqi_flags; unsigned int dqi_bgrace; unsigned int dqi_igrace; union { @@ -165,18 +169,19 @@ struct mem_dqinfo { }; #define DQF_MASK 0xffff /* Mask for format specific flags */ -#define DQF_INFO_DIRTY 0x10000 /* Is info dirty? */ -#define DQF_ANY_DQUOT_DIRTY 0x20000 /* Is any dquot dirty? */ +#define DQF_INFO_DIRTY_B 16 +#define DQF_ANY_DQUOT_DIRTY_B 17 +#define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B) /* Is info dirty? */ +#define DQF_ANY_DQUOT_DIRTY (1 << DQF_ANY_DQUOT_DIRTY B) /* Is any dquot dirty? */ extern inline void mark_info_dirty(struct mem_dqinfo *info) { - info->dqi_flags |= DQF_INFO_DIRTY; + set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags); } -#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY) - -#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\ - (info)->dqi_flags & DQF_ANY_DQUOT_DIRTY) +#define info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags) +#define info_any_dquot_dirty(info) test_bit(DQF_ANY_DQUOT_DIRTY_B, &(info)->dqi_flags) +#define info_any_dirty(info) (info_dirty(info) || info_any_dquot_dirty(info)) #define sb_dqopt(sb) (&(sb)->s_dquot) @@ -195,30 +200,29 @@ extern struct dqstats dqstats; #define NR_DQHASH 43 /* Just an arbitrary number */ -#define DQ_LOCKED 0x01 /* dquot under IO */ -#define DQ_MOD 0x02 /* dquot modified since read */ -#define DQ_BLKS 0x10 /* uid/gid has been warned about blk limit */ -#define DQ_INODES 0x20 /* uid/gid has been warned about inode limit */ -#define DQ_FAKE 0x40 /* no limits only usage */ -#define DQ_INVAL 0x80 /* dquot is going to be invalidated */ +#define DQ_MOD_B 0 +#define DQ_BLKS_B 1 +#define DQ_INODES_B 2 +#define DQ_FAKE_B 3 + +#define DQ_MOD (1 << DQ_MOD_B) /* dquot modified since read */ +#define DQ_BLKS (1 << DQ_BLKS_B) /* uid/gid has been warned about blk limit */ +#define DQ_INODES (1 << DQ_INODES_B) /* uid/gid has been warned about inode limit */ +#define DQ_FAKE (1 << DQ_FAKE_B) /* no limits only usage */ struct dquot { struct list_head dq_hash; /* Hash list in memory */ struct list_head dq_inuse; /* List of all quotas */ struct list_head dq_free; /* Free list element */ - wait_queue_head_t dq_wait_lock; /* Pointer to waitqueue on dquot lock */ - wait_queue_head_t dq_wait_free; /* Pointer to waitqueue for quota to be unused */ - int dq_count; /* Use count */ - int dq_dup_ref; /* Number of duplicated refences */ + struct semaphore dq_lock; /* dquot IO lock */ + atomic_t dq_count; /* Use count */ /* fields after this point are cleared when invalidating */ struct super_block *dq_sb; /* superblock this applies to */ unsigned int dq_id; /* ID this applies to (uid, gid) */ loff_t dq_off; /* Offset of dquot on disk */ + unsigned long dq_flags; /* See DQ_* */ short dq_type; /* Type of quota */ - short dq_flags; /* See DQ_* */ - unsigned long dq_referenced; /* Number of times this dquot was - referenced during its lifetime */ struct mem_dqblk dq_dqb; /* Diskquota usage */ }; @@ -276,7 +280,7 @@ struct quota_format_type { struct quota_info { unsigned int flags; /* Flags for diskquotas on this device */ struct semaphore dqio_sem; /* lock device while I/O in progress */ - struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ + struct rw_semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device and ops using quota_info struct, pointers from inode to dquots */ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ @@ -284,26 +288,17 @@ struct quota_info { /* Inline would be better but we need to dereference super_block which is not defined yet */ #define mark_dquot_dirty(dquot) do {\ - dquot->dq_flags |= DQ_MOD;\ - sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\ + set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->info[(dquot)->dq_type].dqi_flags));\ + set_bit(DQ_MOD_B, &(dquot)->dq_flags);\ } while (0) -#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD) - -static inline int is_enabled(struct quota_info *dqopt, int type) -{ - switch (type) { - case USRQUOTA: - return dqopt->flags & DQUOT_USR_ENABLED; - case GRPQUOTA: - return dqopt->flags & DQUOT_GRP_ENABLED; - } - return 0; -} +#define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags) -#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA)) +#define sb_has_quota_enabled(sb, type) ((type)==USRQUOTA ? \ + (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) : (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED)) -#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type)) +#define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \ + sb_has_quota_enabled(sb, GRPQUOTA)) int register_quota_format(struct quota_format_type *fmt); void unregister_quota_format(struct quota_format_type *fmt); diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 31b24e37c159..e1c502012025 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -46,36 +46,31 @@ static __inline__ void DQUOT_INIT(struct inode *inode) { if (!inode->i_sb) BUG(); - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) inode->i_sb->dq_op->initialize(inode, -1); - unlock_kernel(); } static __inline__ void DQUOT_DROP(struct inode *inode) { - lock_kernel(); if (IS_QUOTAINIT(inode)) { if (!inode->i_sb) BUG(); inode->i_sb->dq_op->drop(inode); /* Ops must be set when there's any quota... */ } - unlock_kernel(); } static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { /* Used space is updated in alloc_space() */ - if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) { - unlock_kernel(); + if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) return 1; - } } - else + else { + spin_lock(&dq_data_lock); inode_add_bytes(inode, nr); - unlock_kernel(); + spin_unlock(&dq_data_lock); + } return 0; } @@ -89,17 +84,16 @@ static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { /* Used space is updated in alloc_space() */ - if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) { - unlock_kernel(); + if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) return 1; - } } - else + else { + spin_lock(&dq_data_lock); inode_add_bytes(inode, nr); - unlock_kernel(); + spin_unlock(&dq_data_lock); + } return 0; } @@ -113,26 +107,23 @@ static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { DQUOT_INIT(inode); - if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { - unlock_kernel(); + if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) return 1; - } } - unlock_kernel(); return 0; } static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) inode->i_sb->dq_op->free_space(inode, nr); - else + else { + spin_lock(&dq_data_lock); inode_sub_bytes(inode, nr); - unlock_kernel(); + spin_unlock(&dq_data_lock); + } } static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) @@ -143,23 +134,17 @@ static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) static __inline__ void DQUOT_FREE_INODE(struct inode *inode) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) inode->i_sb->dq_op->free_inode(inode, 1); - unlock_kernel(); } static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr) { - lock_kernel(); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { DQUOT_INIT(inode); - if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) { - unlock_kernel(); + if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) return 1; - } } - unlock_kernel(); return 0; } @@ -169,10 +154,8 @@ static __inline__ int DQUOT_OFF(struct super_block *sb) { int ret = -ENOSYS; - lock_kernel(); if (sb->s_qcop && sb->s_qcop->quota_off) ret = sb->s_qcop->quota_off(sb, -1); - unlock_kernel(); return ret; } @@ -192,9 +175,7 @@ static __inline__ int DQUOT_OFF(struct super_block *sb) #define DQUOT_TRANSFER(inode, iattr) (0) extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); inode_add_bytes(inode, nr); - unlock_kernel(); return 0; } @@ -207,9 +188,7 @@ extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); inode_add_bytes(inode, nr); - unlock_kernel(); return 0; } @@ -222,9 +201,7 @@ extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - lock_kernel(); inode_sub_bytes(inode, nr); - unlock_kernel(); } extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) diff --git a/include/net/irda/vlsi_ir.h b/include/net/irda/vlsi_ir.h index 32d30cbc0920..f2c66f9296ed 100644 --- a/include/net/irda/vlsi_ir.h +++ b/include/net/irda/vlsi_ir.h @@ -27,13 +27,6 @@ #ifndef IRDA_VLSI_FIR_H #define IRDA_VLSI_FIR_H -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,4) -#ifdef CONFIG_PROC_FS -/* PDE() introduced in 2.5.4 */ -#define PDE(inode) ((inode)->u.generic_ip) -#endif -#endif - /* * #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,xx) * diff --git a/kernel/acct.c b/kernel/acct.c index 9e9276d635f7..8c51231fc0b2 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -50,6 +50,7 @@ #include <linux/file.h> #include <linux/tty.h> #include <linux/security.h> +#include <linux/vfs.h> #include <asm/uaccess.h> /* diff --git a/kernel/module.c b/kernel/module.c index 6d2e66e9bf37..680deb635e30 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1,4 +1,5 @@ /* Rewritten by Rusty Russell, on the backs of many others... + Copyright (C) 2002 Richard Henderson Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. This program is free software; you can redistribute it and/or modify @@ -27,6 +28,8 @@ #include <linux/rcupdate.h> #include <linux/cpu.h> #include <linux/moduleparam.h> +#include <linux/errno.h> +#include <linux/err.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #include <asm/pgalloc.h> @@ -38,6 +41,13 @@ #define DEBUGP(fmt , a...) #endif +#ifndef ARCH_SHF_SMALL +#define ARCH_SHF_SMALL 0 +#endif + +/* If this is set, the section belongs in the init part of the module */ +#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) + #define symbol_is(literal, string) \ (strcmp(MODULE_SYMBOL_PREFIX literal, (string)) == 0) @@ -53,13 +63,6 @@ static inline int strong_try_module_get(struct module *mod) return try_module_get(mod); } -/* Convenient structure for holding init and core sizes */ -struct sizes -{ - unsigned long init_size; - unsigned long core_size; -}; - /* Stub function for modules which don't have an initfn */ int init_module(void) { @@ -94,7 +97,7 @@ static unsigned long find_local_symbol(Elf_Shdr *sechdrs, const char *name) { unsigned int i; - Elf_Sym *sym = (void *)sechdrs[symindex].sh_offset; + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; /* Search (defined) internal symbols first. */ for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) { @@ -764,43 +767,6 @@ void *__symbol_get(const char *symbol) } EXPORT_SYMBOL_GPL(__symbol_get); -/* Transfer one ELF section to the correct (init or core) area. */ -static void *copy_section(const char *name, - void *base, - Elf_Shdr *sechdr, - struct module *mod, - struct sizes *used) -{ - void *dest; - unsigned long *use; - unsigned long max; - - /* Only copy to init section if there is one */ - if (strstr(name, ".init") && mod->module_init) { - dest = mod->module_init; - use = &used->init_size; - max = mod->init_size; - } else { - dest = mod->module_core; - use = &used->core_size; - max = mod->core_size; - } - - /* Align up */ - *use = ALIGN(*use, sechdr->sh_addralign); - dest += *use; - *use += sechdr->sh_size; - - if (*use > max) - return ERR_PTR(-ENOEXEC); - - /* May not actually be in the file (eg. bss). */ - if (sechdr->sh_type != SHT_NOBITS) - memcpy(dest, base + sechdr->sh_offset, sechdr->sh_size); - - return dest; -} - /* Deal with the given section */ static int handle_section(const char *name, Elf_Shdr *sechdrs, @@ -810,7 +776,7 @@ static int handle_section(const char *name, struct module *mod) { int ret; - const char *strtab = (char *)sechdrs[strindex].sh_offset; + const char *strtab = (char *)sechdrs[strindex].sh_addr; switch (sechdrs[i].sh_type) { case SHT_REL: @@ -840,38 +806,11 @@ static int handle_section(const char *name, return ret; } -/* Figure out total size desired for the common vars */ -static unsigned long read_commons(void *start, Elf_Shdr *sechdr) -{ - unsigned long size, i, max_align; - Elf_Sym *sym; - - size = max_align = 0; - - for (sym = start + sechdr->sh_offset, i = 0; - i < sechdr->sh_size / sizeof(Elf_Sym); - i++) { - if (sym[i].st_shndx == SHN_COMMON) { - /* Value encodes alignment. */ - if (sym[i].st_value > max_align) - max_align = sym[i].st_value; - /* Pad to required alignment */ - size = ALIGN(size, sym[i].st_value) + sym[i].st_size; - } - } - - /* Now, add in max alignment requirement (with align - attribute, this could be large), so we know we have space - whatever the start alignment is */ - return size + max_align; -} - /* Change all symbols so that sh_value encodes the pointer directly. */ -static void simplify_symbols(Elf_Shdr *sechdrs, - unsigned int symindex, - unsigned int strindex, - void *common, - struct module *mod) +static int simplify_symbols(Elf_Shdr *sechdrs, + unsigned int symindex, + unsigned int strindex, + struct module *mod) { unsigned int i; Elf_Sym *sym; @@ -879,18 +818,15 @@ static void simplify_symbols(Elf_Shdr *sechdrs, /* First simplify defined symbols, so if they become the "answer" to undefined symbols, copying their st_value us correct. */ - for (sym = (void *)sechdrs[symindex].sh_offset, i = 0; + for (sym = (void *)sechdrs[symindex].sh_addr, i = 0; i < sechdrs[symindex].sh_size / sizeof(Elf_Sym); i++) { switch (sym[i].st_shndx) { case SHN_COMMON: - /* Value encodes alignment. */ - common = (void *)ALIGN((unsigned long)common, - sym[i].st_value); - /* Change it to encode pointer */ - sym[i].st_value = (unsigned long)common; - common += sym[i].st_size; - break; + /* We compiled with -fno-common. These are not + supposed to happen. */ + DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name); + return -ENOEXEC; case SHN_ABS: /* Don't need to do anything */ @@ -904,20 +840,20 @@ static void simplify_symbols(Elf_Shdr *sechdrs, default: sym[i].st_value = (unsigned long) - (sechdrs[sym[i].st_shndx].sh_offset + (sechdrs[sym[i].st_shndx].sh_addr + sym[i].st_value); } } /* Now try to resolve undefined symbols */ - for (sym = (void *)sechdrs[symindex].sh_offset, i = 0; + for (sym = (void *)sechdrs[symindex].sh_addr, i = 0; i < sechdrs[symindex].sh_size / sizeof(Elf_Sym); i++) { if (sym[i].st_shndx == SHN_UNDEF) { /* Look for symbol */ struct kernel_symbol_group *ksg = NULL; const char *strtab - = (char *)sechdrs[strindex].sh_offset; + = (char *)sechdrs[strindex].sh_addr; sym[i].st_value = find_symbol_internal(sechdrs, @@ -928,36 +864,70 @@ static void simplify_symbols(Elf_Shdr *sechdrs, &ksg); } } + + return 0; } -/* Get the total allocation size of the init and non-init sections */ -static struct sizes get_sizes(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - const char *secstrings, - unsigned long common_length) +/* Update size with this section: return offset. */ +static long get_offset(unsigned long *size, Elf_Shdr *sechdr) { - struct sizes ret = { 0, common_length }; - unsigned i; - - /* Everything marked ALLOC (this includes the exported - symbols) */ - for (i = 1; i < hdr->e_shnum; i++) { - unsigned long *add; + long ret; - /* If it's called *.init*, and we're init, we're interested */ - if (strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) - add = &ret.init_size; - else - add = &ret.core_size; + ret = ALIGN(*size, sechdr->sh_addralign ?: 1); + *size = ret + sechdr->sh_size; + return ret; +} - if (sechdrs[i].sh_flags & SHF_ALLOC) { - /* Pad up to required alignment */ - *add = ALIGN(*add, sechdrs[i].sh_addralign ?: 1); - *add += sechdrs[i].sh_size; +/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld + might -- code, read-only data, read-write data, small data. Tally + sizes, and place the offsets into sh_link fields: high bit means it + belongs in init. */ +static void layout_sections(struct module *mod, + const Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + const char *secstrings) +{ + static unsigned long const masks[][2] = { + { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, + { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, + { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, + { ARCH_SHF_SMALL | SHF_ALLOC, 0 } + }; + unsigned int m, i; + + for (i = 0; i < hdr->e_shnum; i++) + sechdrs[i].sh_link = ~0UL; + + DEBUGP("Core section allocation order:\n"); + for (m = 0; m < ARRAY_SIZE(masks); ++m) { + for (i = 0; i < hdr->e_shnum; ++i) { + Elf_Shdr *s = &sechdrs[i]; + + if ((s->sh_flags & masks[m][0]) != masks[m][0] + || (s->sh_flags & masks[m][1]) + || s->sh_link != ~0UL + || strstr(secstrings + s->sh_name, ".init")) + continue; + s->sh_link = get_offset(&mod->core_size, s); + DEBUGP("\t%s\n", name); } } - return ret; + DEBUGP("Init section allocation order:\n"); + for (m = 0; m < ARRAY_SIZE(masks); ++m) { + for (i = 0; i < hdr->e_shnum; ++i) { + Elf_Shdr *s = &sechdrs[i]; + + if ((s->sh_flags & masks[m][0]) != masks[m][0] + || (s->sh_flags & masks[m][1]) + || s->sh_link != ~0UL + || !strstr(secstrings + s->sh_name, ".init")) + continue; + s->sh_link = (get_offset(&mod->init_size, s) + | INIT_OFFSET_MASK); + DEBUGP("\t%s\n", name); + } + } } /* Allocate and load the module */ @@ -971,8 +941,6 @@ static struct module *load_module(void *umod, unsigned int i, symindex, exportindex, strindex, setupindex, exindex, modindex, obsparmindex; long arglen; - unsigned long common_length; - struct sizes sizes, used; struct module *mod; long err = 0; void *ptr = NULL; /* Stops spurious gcc uninitialized warning */ @@ -1014,6 +982,10 @@ static struct module *load_module(void *umod, /* Find where important sections are */ for (i = 1; i < hdr->e_shnum; i++) { + /* Mark all sections sh_addr with their address in the + temporary image. */ + sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset; + if (sechdrs[i].sh_type == SHT_SYMTAB) { /* Internal symbols */ DEBUGP("Symbol table in section %u\n", i); @@ -1064,7 +1036,7 @@ static struct module *load_module(void *umod, err = -ENOEXEC; goto free_hdr; } - mod = (void *)hdr + sechdrs[modindex].sh_offset; + mod = (void *)sechdrs[modindex].sh_addr; /* Now copy in args */ err = strlen_user(uargs); @@ -1089,24 +1061,15 @@ static struct module *load_module(void *umod, mod->state = MODULE_STATE_COMING; - /* How much space will we need? (Common area in first) */ - common_length = read_commons(hdr, &sechdrs[symindex]); - sizes = get_sizes(hdr, sechdrs, secstrings, common_length); - - /* Set these up, and allow archs to manipulate them. */ - mod->core_size = sizes.core_size; - mod->init_size = sizes.init_size; - - /* Allow archs to add to them. */ - err = module_init_size(hdr, sechdrs, secstrings, mod); + /* Allow arches to frob section contents and sizes. */ + err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod); if (err < 0) goto free_mod; - mod->init_size = err; - err = module_core_size(hdr, sechdrs, secstrings, mod); - if (err < 0) - goto free_mod; - mod->core_size = err; + /* Determine total sizes, and put offsets in sh_link. For now + this is done generically; there doesn't appear to be any + special cases for the architectures. */ + layout_sections(mod, hdr, sechdrs, secstrings); /* Do the allocs. */ ptr = module_alloc(mod->core_size); @@ -1125,39 +1088,41 @@ static struct module *load_module(void *umod, memset(ptr, 0, mod->init_size); mod->module_init = ptr; - /* Transfer each section which requires ALLOC, and set sh_offset - fields to absolute addresses. */ - used.core_size = common_length; - used.init_size = 0; - for (i = 1; i < hdr->e_shnum; i++) { - if (sechdrs[i].sh_flags & SHF_ALLOC) { - ptr = copy_section(secstrings + sechdrs[i].sh_name, - hdr, &sechdrs[i], mod, &used); - if (IS_ERR(ptr)) - goto cleanup; - sechdrs[i].sh_offset = (unsigned long)ptr; - /* Have we just copied __this_module across? */ - if (i == modindex) - mod = ptr; - } else { - sechdrs[i].sh_offset += (unsigned long)hdr; - } + /* Transfer each section which specifies SHF_ALLOC */ + for (i = 0; i < hdr->e_shnum; i++) { + void *dest; + + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + + if (sechdrs[i].sh_link & INIT_OFFSET_MASK) + dest = mod->module_init + + (sechdrs[i].sh_link & ~INIT_OFFSET_MASK); + else + dest = mod->module_core + sechdrs[i].sh_link; + + if (sechdrs[i].sh_type != SHT_NOBITS) + memcpy(dest, (void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size); + /* Update sh_addr to point to copy in image. */ + sechdrs[i].sh_addr = (unsigned long)dest; } - /* Don't use more than we allocated! */ - if (used.init_size > mod->init_size || used.core_size > mod->core_size) - BUG(); + /* Module has been moved. */ + mod = (void *)sechdrs[modindex].sh_addr; /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); /* Fix up syms, so that st_value is a pointer to location. */ - simplify_symbols(sechdrs, symindex, strindex, mod->module_core, mod); + 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_offset; + mod->symbols.syms = (void *)sechdrs[exportindex].sh_addr; } /* Set up exception table */ @@ -1166,7 +1131,7 @@ static struct module *load_module(void *umod, mod->extable.num_entries = (sechdrs[exindex].sh_size / sizeof(struct exception_table_entry)); - mod->extable.entry = (void *)sechdrs[exindex].sh_offset; + mod->extable.entry = (void *)sechdrs[exindex].sh_addr; } /* Now handle each section. */ @@ -1178,9 +1143,9 @@ static struct module *load_module(void *umod, } #ifdef CONFIG_KALLSYMS - mod->symtab = (void *)sechdrs[symindex].sh_offset; + mod->symtab = (void *)sechdrs[symindex].sh_addr; mod->num_syms = sechdrs[symindex].sh_size / sizeof(Elf_Sym); - mod->strtab = (void *)sechdrs[strindex].sh_offset; + mod->strtab = (void *)sechdrs[strindex].sh_addr; #endif err = module_finalize(hdr, sechdrs, mod); if (err < 0) @@ -1190,16 +1155,16 @@ static struct module *load_module(void *umod, if (obsparmindex) { err = obsolete_params(mod->name, mod->args, (struct obsolete_modparm *) - sechdrs[obsparmindex].sh_offset, + sechdrs[obsparmindex].sh_addr, sechdrs[obsparmindex].sh_size / sizeof(struct obsolete_modparm), sechdrs, symindex, - (char *)sechdrs[strindex].sh_offset); + (char *)sechdrs[strindex].sh_addr); } else { /* Size of section 0 is 0, so this works well if no params */ err = parse_args(mod->name, mod->args, (struct kernel_param *) - sechdrs[setupindex].sh_offset, + sechdrs[setupindex].sh_addr, sechdrs[setupindex].sh_size / sizeof(struct kernel_param), NULL); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b7e6d06581dc..0889e9e5a2e7 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -521,7 +521,7 @@ int vsscanf(const char * buf, const char * fmt, va_list args) int num = 0; int qualifier; int base; - int field_width = -1; + int field_width; int is_sign = 0; while(*fmt && *str) { @@ -559,6 +559,7 @@ int vsscanf(const char * buf, const char * fmt, va_list args) } /* get field width */ + field_width = -1; if (isdigit(*fmt)) field_width = skip_atoi(&fmt); diff --git a/mm/shmem.c b/mm/shmem.c index 987203cb2a41..d283ef97b644 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -32,7 +32,7 @@ #include <linux/shmem_fs.h> #include <linux/mount.h> #include <linux/writeback.h> - +#include <linux/vfs.h> #include <asm/uaccess.h> /* This magic number is used in glibc for posix shared memory */ |
