summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2003-01-01 21:59:24 -0600
committerPatrick Mochel <mochel@osdl.org>2003-01-01 21:59:24 -0600
commit5816344d714eaf45f2305ac2215894e41c4fd297 (patch)
treeccd8b9c30cfdfba2a1271e0015ff9932fb284cf0
parent20d7bffcf7a196e0a6a20baebfe3e00c0919253c (diff)
parent4c55cc628bf2eaa15a8d5814974ad61e71d7e30c (diff)
Merge bk://linux.bkbits.net/linux-2.5
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/kernel/osf_sys.c1
-rw-r--r--arch/arm/kernel/module.c22
-rw-r--r--arch/i386/kernel/module.c24
-rw-r--r--arch/ia64/ia32/sys_ia32.c1
-rw-r--r--arch/mips/kernel/sysirix.c1
-rw-r--r--arch/mips64/kernel/linux32.c1
-rw-r--r--arch/parisc/hpux/sys_hpux.c1
-rw-r--r--arch/parisc/kernel/sys_parisc32.c1
-rw-r--r--arch/ppc/kernel/module.c59
-rw-r--r--arch/s390/kernel/module.c27
-rw-r--r--arch/s390x/kernel/linux32.c1
-rw-r--r--arch/s390x/kernel/module.c26
-rw-r--r--arch/sparc/kernel/module.c24
-rw-r--r--arch/sparc64/kernel/module.c24
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c1
-rw-r--r--arch/sparc64/solaris/fs.c1
-rw-r--r--arch/v850/kernel/module.c6
-rw-r--r--arch/x86_64/ia32/sys_ia32.c1
-rw-r--r--arch/x86_64/kernel/module.c24
-rw-r--r--drivers/media/radio/miropcm20-rds.c3
-rw-r--r--drivers/message/fusion/linux_compat.h33
-rw-r--r--drivers/message/fusion/mptbase.c327
-rw-r--r--drivers/message/fusion/mptbase.h21
-rw-r--r--drivers/message/fusion/mptctl.c6
-rw-r--r--drivers/message/fusion/mptctl.h2
-rw-r--r--drivers/message/fusion/mptscsih.c1328
-rw-r--r--drivers/message/fusion/mptscsih.h38
-rw-r--r--drivers/net/ppp_generic.c2
-rw-r--r--drivers/net/pppox.c11
-rw-r--r--drivers/net/slhc.c4
-rw-r--r--drivers/video/i810/Makefile2
-rw-r--r--fs/adfs/super.c1
-rw-r--r--fs/affs/super.c1
-rw-r--r--fs/befs/linuxvfs.c1
-rw-r--r--fs/bfs/inode.c1
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c1
-rw-r--r--fs/coda/inode.c1
-rw-r--r--fs/coda/upcall.c1
-rw-r--r--fs/cramfs/inode.c1
-rw-r--r--fs/devfs/base.c141
-rw-r--r--fs/dquot.c691
-rw-r--r--fs/efs/super.c1
-rw-r--r--fs/ext2/super.c1
-rw-r--r--fs/ext3/super.c1
-rw-r--r--fs/fat/inode.c1
-rw-r--r--fs/freevxfs/vxfs_super.c1
-rw-r--r--fs/hfs/super.c1
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/super.c1
-rw-r--r--fs/inode.c4
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/jffs/inode-v23.c1
-rw-r--r--fs/jffs2/fs.c1
-rw-r--r--fs/jffs2/os-linux.h1
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/libfs.c2
-rw-r--r--fs/minix/inode.c1
-rw-r--r--fs/ncpfs/inode.c1
-rw-r--r--fs/nfs/inode.c1
-rw-r--r--fs/nfsd/nfs3xdr.c2
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsxdr.c2
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/ntfs/super.c1
-rw-r--r--fs/open.c2
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/quota.c9
-rw-r--r--fs/reiserfs/super.c1
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/smbfs/proc.c2
-rw-r--r--fs/smbfs/proto.h1
-rw-r--r--fs/super.c3
-rw-r--r--fs/sysv/inode.c1
-rw-r--r--fs/udf/super.c1
-rw-r--r--fs/ufs/super.c1
-rw-r--r--fs/xfs/linux/xfs_linux.h1
-rw-r--r--include/asm-ppc/module.h13
-rw-r--r--include/linux/coda_psdev.h2
-rw-r--r--include/linux/devfs_fs_kernel.h44
-rw-r--r--include/linux/efs_fs.h2
-rw-r--r--include/linux/ext3_fs.h3
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/moduleloader.h19
-rw-r--r--include/linux/msdos_fs.h3
-rw-r--r--include/linux/nfsd/xdr.h1
-rw-r--r--include/linux/quota.h71
-rw-r--r--include/linux/quotaops.h55
-rw-r--r--include/net/irda/vlsi_ir.h7
-rw-r--r--kernel/acct.c1
-rw-r--r--kernel/module.c277
-rw-r--r--lib/vsprintf.c3
-rw-r--r--mm/shmem.c2
95 files changed, 1825 insertions, 1608 deletions
diff --git a/Makefile b/Makefile
index 800d7669c1e0..fc3c03c93ecd 100644
--- a/Makefile
+++ b/Makefile
@@ -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 = &quota_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 */