From 8a0d09a2420b34d7e7003714b02ab0ba837c0949 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:15:26 -0500 Subject: [PATCH] Import 2.1.100 --- Documentation/Changes | 18 +- arch/alpha/kernel/bios32.c | 4 +- arch/alpha/kernel/ptrace.c | 2 +- arch/arm/kernel/ioport.c | 4 +- arch/arm/kernel/ptrace.c | 2 +- arch/i386/kernel/entry.S | 4 +- arch/i386/kernel/ioport.c | 4 +- arch/i386/kernel/irq.c | 15 +- arch/i386/kernel/ptrace.c | 2 +- arch/i386/kernel/smp.c | 2 + arch/i386/kernel/trampoline.S | 2 +- arch/i386/kernel/vm86.c | 2 +- arch/m68k/kernel/ptrace.c | 2 +- arch/m68k/kernel/sys_m68k.c | 2 +- arch/mips/kernel/ptrace.c | 3 +- arch/mips/kernel/sysirix.c | 4 +- arch/mips/kernel/sysmips.c | 2 +- arch/ppc/kernel/ptrace.c | 2 +- arch/ppc/mm/init.c | 7 +- arch/sparc/kernel/ptrace.c | 3 +- arch/sparc64/kernel/psycho.c | 4 +- arch/sparc64/kernel/ptrace.c | 3 +- arch/sparc64/kernel/sys_sparc32.c | 2 +- arch/sparc64/kernel/traps.c | 2 +- arch/sparc64/solaris/fs.c | 2 +- drivers/acorn/block/fd1772.c | 2 +- drivers/acorn/block/mfmhd.c | 8 +- drivers/ap1000/ddv.c | 2 + drivers/block/acsi.c | 4 +- drivers/block/ali14xx.c | 20 +- drivers/block/ataflop.c | 4 +- drivers/block/dtc2278.c | 12 +- drivers/block/floppy.c | 8 +- drivers/block/hd.c | 6 +- drivers/block/ht6560b.c | 6 +- drivers/block/ide-cd.h | 10 +- drivers/block/ide-disk.c | 31 +- drivers/block/ide-dma.c | 31 +- drivers/block/ide-floppy.c | 2 +- drivers/block/ide-pci.c | 17 +- drivers/block/ide-probe.c | 54 +- drivers/block/ide-proc.c | 87 ++- drivers/block/ide-tape.c | 48 +- drivers/block/ide.c | 701 +++++++++++++++---------- drivers/block/ide.h | 38 +- drivers/block/loop.c | 2 +- drivers/block/md.c | 2 +- drivers/block/nbd.c | 2 +- drivers/block/ns87415.c | 42 +- drivers/block/opti621.c | 6 +- drivers/block/paride/pd.c | 6 +- drivers/block/paride/pf.c | 4 +- drivers/block/pdc4030.c | 10 +- drivers/block/ps2esdi.c | 6 +- drivers/block/qd6580.c | 6 +- drivers/block/rd.c | 2 +- drivers/block/sl82c105.c | 17 +- drivers/block/trm290.c | 19 +- drivers/block/umc8672.c | 16 +- drivers/block/xd.c | 8 +- drivers/cdrom/sbpcd.c | 4 +- drivers/char/apm_bios.c | 2 +- drivers/char/bttv.c | 6 +- drivers/char/console.c | 2 +- drivers/char/esp.c | 4 +- drivers/char/ftape/zftape/zftape-ctl.c | 4 +- drivers/char/istallion.c | 2 +- drivers/char/lp.c | 138 +++-- drivers/char/nvram.c | 4 +- drivers/char/random.c | 10 +- drivers/char/riscom8.c | 2 +- drivers/char/rocket.c | 2 +- drivers/char/rtc.c | 8 +- drivers/char/serial.c | 10 +- drivers/char/specialix.c | 2 +- drivers/char/stallion.c | 2 +- drivers/char/vt.c | 5 +- drivers/isdn/avmb1/capi.c | 2 +- drivers/macintosh/macserial.c | 2 +- drivers/misc/TODO-parport | 11 +- drivers/net/3c509.c | 278 ++++------ drivers/net/3c59x.c | 2 +- drivers/net/de4x5.c | 12 +- drivers/net/depca.c | 14 +- drivers/net/dlci.c | 4 +- drivers/net/eepro100.c | 2 +- drivers/net/eql.c | 3 +- drivers/net/ewrk3.c | 20 +- drivers/net/ipddp.c | 2 +- drivers/net/ppp.c | 2 +- drivers/pci/proc.c | 2 +- drivers/sbus/char/rtc.c | 2 +- drivers/sbus/char/vfc_dev.c | 2 +- drivers/sbus/char/zs.c | 2 +- drivers/scsi/ide-scsi.c | 2 +- drivers/scsi/ppa.c | 16 +- drivers/scsi/scsi_ioctl.c | 6 +- drivers/scsi/sd_ioctl.c | 6 +- drivers/scsi/sr_ioctl.c | 4 +- drivers/scsi/st.c | 2 +- drivers/sgi/char/sgiserial.c | 2 +- fs/affs/namei.c | 4 +- fs/attr.c | 12 +- fs/autofs/root.c | 2 +- fs/buffer.c | 2 +- fs/dquot.c | 23 +- fs/exec.c | 60 ++- fs/ext2/acl.c | 9 +- fs/ext2/balloc.c | 3 +- fs/ext2/file.c | 2 +- fs/ext2/inode.c | 4 +- fs/ext2/ioctl.c | 7 +- fs/ext2/namei.c | 8 +- fs/minix/namei.c | 8 +- fs/namei.c | 9 +- fs/nfsd/nfsctl.c | 2 +- fs/open.c | 15 +- fs/proc/array.c | 12 + fs/proc/inode.c | 7 +- fs/smbfs/proc.c | 3 +- fs/super.c | 4 +- fs/sysv/namei.c | 8 +- fs/umsdos/namei.c | 8 +- include/asm-alpha/ide.h | 2 +- include/asm-alpha/mmu_context.h | 12 + include/asm-arm/ide.h | 2 +- include/asm-arm/mmu_context.h | 1 + include/asm-i386/ide.h | 2 +- include/asm-i386/mmu_context.h | 1 + include/asm-i386/spinlock.h | 68 ++- include/asm-i386/unistd.h | 2 + include/asm-m68k/ide.h | 8 +- include/asm-m68k/mmu_context.h | 1 + include/asm-mips/ide.h | 2 +- include/asm-mips/mmu_context.h | 10 + include/asm-ppc/ide.h | 2 +- include/asm-ppc/mmu_context.h | 38 +- include/asm-sparc/mmu_context.h | 7 + include/asm-sparc64/ide.h | 4 +- include/asm-sparc64/mmu_context.h | 6 + include/linux/blk.h | 22 +- include/linux/capability.h | 154 +++++- include/linux/hdreg.h | 9 +- include/linux/lp.h | 18 +- include/linux/proc_fs.h | 5 +- include/linux/sched.h | 2 +- ipc/msg.c | 7 +- ipc/sem.c | 6 +- ipc/shm.c | 10 +- ipc/util.c | 4 +- kernel/Makefile | 2 +- kernel/acct.c | 2 +- kernel/capability.c | 252 +++++++++ kernel/fork.c | 8 +- kernel/module.c | 6 +- kernel/printk.c | 2 +- kernel/sched.c | 7 +- kernel/signal.c | 2 +- kernel/sys.c | 113 +++- kernel/time.c | 6 +- mm/mlock.c | 4 +- mm/page_alloc.c | 4 +- mm/swapfile.c | 4 +- net/appletalk/ddp.c | 6 +- net/core/dev.c | 4 +- net/core/scm.c | 17 +- net/core/sock.c | 4 +- net/ipv4/af_inet.c | 9 +- net/ipv4/devinet.c | 4 +- net/ipv4/fib_frontend.c | 2 +- net/ipv4/ip_sockglue.c | 9 +- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/addrconf.c | 4 +- net/ipv6/af_inet6.c | 7 +- net/ipv6/route.c | 2 +- net/packet/af_packet.c | 5 +- net/rose/af_rose.c | 2 +- net/wanrouter/wanmain.c | 2 +- net/x25/af_x25.c | 2 +- 180 files changed, 1907 insertions(+), 1150 deletions(-) create mode 100644 kernel/capability.c diff --git a/Documentation/Changes b/Documentation/Changes index 8bd1786ed79c..1da1ddf7ee8c 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -33,7 +33,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well. Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: April 27, 1998 +Last updated: May 5, 1998 Current Author: Chris Ricker (kaboom@gatech.edu). Current Minimal Requirements @@ -60,7 +60,7 @@ running, the suggested command should tell you. - Bash 1.14.7 ; bash -version - Ncpfs 2.1.1 ; ncpmount -v - Pcmcia-cs 3.0.0 -- PPP 2.3.3 ; pppd -v +- PPP 2.3.5 ; pppd -v Upgrade notes ************* @@ -127,6 +127,12 @@ Binutils to find out the proper way to upgrade it. No, the instruction to "rm `which encaps`" is not a joke. +The last public release of the binutils 2.8.x series is 2.8.1.0.23. +Binutils 2.8.1.0.25 to 2.9.1.0.2 are all very buggy; do not use them. +Binutils 2.9.1 (note the absence of a suffix) is all right, and binutils +2.9.1.0.3 (and presumably later revisions) will probably work, too. +Stick with 2.8.1.0.23 to be safe. + Gnu C ===== @@ -423,14 +429,14 @@ ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz Pcmcia-cs ========= -The 3.0.0 release: -ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-3.0.0.tar.gz +The May 4, 1998 release: +ftp://hyper.stanford.edu/pub/pcmcia/NEW/pcmcia-cs.04-May-98.tar.gz PPP === -The 2.3.3 release: -ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.3.tar.gz +The 2.3.5 release: +ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz Other Info ========== diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 46880f11e636..64c7442b6458 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -2041,7 +2041,7 @@ asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned int uint; long err = 0; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); @@ -2082,7 +2082,7 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned int uint; long err = 0; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 38cb5e05d243..c8b31623d25e 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -506,7 +506,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/arm/kernel/ioport.c b/arch/arm/kernel/ioport.c index defa74335cce..fe88df1731bc 100644 --- a/arch/arm/kernel/ioport.c +++ b/arch/arm/kernel/ioport.c @@ -58,7 +58,7 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) if (from + num > IO_BITMAP_SIZE*32) return -EINVAL; #endif - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; #ifdef IODEBUG @@ -91,7 +91,7 @@ asmlinkage int sys_iopl(long ebx,long ecx,long edx, if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; *(&eflags) = (eflags & 0xffffcfff) | (level << 12); return 0; diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index f95e8de7e0e0..9ca7bc964677 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -581,7 +581,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index b6541005fbb5..b3848c945b7a 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -544,7 +544,9 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_pwrite) .long SYMBOL_NAME(sys_chown) .long SYMBOL_NAME(sys_getcwd) + .long SYMBOL_NAME(sys_capget) + .long SYMBOL_NAME(sys_capset) /* 185 */ - .rept NR_syscalls-182 + .rept NR_syscalls-184 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index 19587312a0da..2e3beb11b8ee 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -58,7 +58,7 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* * If it's the first ioperm() call in this thread's lifetime, set the @@ -94,7 +94,7 @@ asmlinkage int sys_iopl(unsigned long unused) if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 94736ed09e77..fddc57c1feca 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -356,13 +356,14 @@ int get_irq_list(char *buf) p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #endif - if (IO_APIC_IRQ(i)) { p += sprintf(p, " IO-APIC"); +#ifdef __SMP__ if (irq_desc[i].handler == &ioapic_level_irq_type) p += sprintf(p, "-level "); else p += sprintf(p, "-edge "); +#endif } else p += sprintf(p, " XT-PIC "); p += sprintf(p, " %s", action->name); @@ -770,15 +771,25 @@ static void disable_edge_ioapic_irq(unsigned int irq) { } +/* + * if we enable this, why does it cause a hang in the BusLogic + * driver, when level triggered PCI IRQs are used? + */ +#define NOT_BROKEN 0 + static void enable_level_ioapic_irq(unsigned int irq) { +#if NOT_BROKEN enable_IO_APIC_irq(irq); +#endif self_IPI(irq); } static void disable_level_ioapic_irq(unsigned int irq) { +#if NOT_BROKEN disable_IO_APIC_irq(irq); +#endif } /* @@ -855,7 +866,9 @@ static void do_level_ioapic_IRQ (unsigned int irq, int cpu, * in the IO-APIC, then we 'early ACK' the IRQ, then we * handle it and enable the IRQ when finished. */ +#if NOT_BROKEN disable_IO_APIC_irq(irq); +#endif ack_APIC_irq(); desc->ipi = 0; diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index d05b54b63140..294043faf33b 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -386,7 +386,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 2e862ca166ab..ec7ee88c4cb4 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -439,6 +439,8 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) { unsigned long cfg; + /* local APIC has default address */ + mp_lapic_addr = 0xFEE00000; /* * We need to know what the local * APIC id of the boot CPU is! diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S index 1f5303a9edcb..12c1dbe343f6 100644 --- a/arch/i386/kernel/trampoline.S +++ b/arch/i386/kernel/trampoline.S @@ -54,7 +54,7 @@ r_base = . lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmp $__KERNEL_CS, $0x00100000 + ljmpl $__KERNEL_CS, $0x00100000 # jump to startup_32 idt_48: diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index db7da10fc2c1..03bab3454d57 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -660,7 +660,7 @@ static int do_vm86_irq_handling(int subfunction, int irqnumber) int sig = irqnumber >> 8; int irq = irqnumber & 255; handle_irq_zombies(); - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM; if ( (irq<3) || (irq>15) ) return -EPERM; if (vm86_irqs[irq].tsk) return -EPERM; diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 090f060ad50c..4a2a95f4b038 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -340,7 +340,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index b28a433742cc..50d56413448e 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -548,7 +548,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) if (scope == FLUSH_SCOPE_ALL) { /* Only the superuser may flush the whole cache. */ ret = -EPERM; - if (!suser ()) + if (!capable(CAP_SYS_ADMIN)) goto out; } else { /* Verify that the specified address region actually belongs to diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index b5a5a442889c..8d28a16aa479 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -289,7 +289,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { res = -EPERM; goto out; } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index c8f92bd8f337..72869c3690c6 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -113,7 +113,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs) current->comm, current->pid, (unsigned long) value); if(value > RLIM_INFINITY) value = RLIM_INFINITY; - if(suser()) { + if(capable(CAP_SYS_ADMIN)) { current->rlim[RLIMIT_STACK].rlim_max = current->rlim[RLIMIT_STACK].rlim_cur = value; error = value; @@ -545,7 +545,7 @@ asmlinkage int irix_stime(int value) int ret; lock_kernel(); - if(!suser()) { + if(!capable(CAP_SYS_TIME)) { ret = -EPERM; goto out; } diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c index 62f8687c07c1..25e48cb04d5f 100644 --- a/arch/mips/kernel/sysmips.c +++ b/arch/mips/kernel/sysmips.c @@ -58,7 +58,7 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) { case SETNAME: retval = -EPERM; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; name = (char *) arg1; diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index ce2f35058f1d..66dfb630fb7c 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -331,7 +331,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 5967e29e6427..d13d8782130d 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1296,11 +1296,8 @@ local_flush_tlb_mm(struct mm_struct *mm) { #ifndef CONFIG_8xx mm->context = NO_CONTEXT; - if (mm == current->mm) { - get_mmu_context(current); - /* done by get_mmu_context() now -- Cort */ - /*set_context(current->mm->context);*/ - } + if (mm == current->mm) + activate_context(current); #else asm volatile ("tlbia" : : ); #endif diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index e50f308c7243..40e23fa0eec9 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -539,7 +539,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c index 78a69e8df70e..bec1e9fef862 100644 --- a/arch/sparc64/kernel/psycho.c +++ b/arch/sparc64/kernel/psycho.c @@ -2323,7 +2323,7 @@ asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned int uint; int err = 0; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); @@ -2361,7 +2361,7 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned int uint; int err = 0; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 9174e7e452ca..5d3c6f46ab18 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -557,7 +557,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 2844a4bf202c..caad4273650b 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1366,7 +1366,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, unsigned long type_page; int err, is_smb, is_ncp; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; is_smb = is_ncp = 0; err = copy_mount_stuff_to_kernel((const void *)A(type), &type_page); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index b255c76239af..069e908d0db6 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -583,7 +583,7 @@ void cache_flush_trap(struct pt_regs *regs) regs->tpc = regs->tnpc; regs->tnpc = regs->tnpc + 4; - if (!suser()) return; + if (!capable(CAP_SYS_ADMIN)) return; size >>= PAGE_SHIFT; addr = PAGE_OFFSET - PAGE_SIZE; page = mem_map - 1; diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 39e69d2420b9..6df97c7c46f5 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -464,7 +464,7 @@ asmlinkage int solaris_ulimit(int cmd, int val) val <<= 9; lock_kernel(); if (val > current->rlim[RLIMIT_FSIZE].rlim_max) { - if (!suser()) { + if (!capable(CAP_SYS_RESOURCE)) { unlock_kernel(); return -EPERM; } diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 58ad6ce0d95e..765aeba67765 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -1368,7 +1368,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, case FDFLUSH: return invalidate_drive(drive); } - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (drive < 0 || drive > 3) return -EINVAL; diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 82c7e7bf585c..40308c4e1999 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -1206,14 +1206,14 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a return 0; case BLKFLSBUF: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(dev); invalidate_buffers(dev); return 0; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg > 0xff) return -EINVAL; @@ -1227,7 +1227,7 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a return put_user (mfm[minor].nr_sects, (long *)arg); case BLKFRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; max_readahead[major][minor] = arg; return 0; @@ -1239,7 +1239,7 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a return put_user(max_sectors[major][minor], (long *) arg); case BLKRRPART: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; return mfm_reread_partitions(dev); diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c index 2348e21d7646..d58a5b9fb75f 100644 --- a/drivers/ap1000/ddv.c +++ b/drivers/ap1000/ddv.c @@ -856,6 +856,8 @@ static int ddv_ioctl(struct inode *inode, struct file *file, case BLKRRPART: printk("\tBLKRRPART\n"); + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return ddv_revalidate(inode->i_rdev,&ddv_gendisk); case BLKGETSIZE: /* Return device size */ diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index f04c0347feb0..432276973a29 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1149,13 +1149,15 @@ static int acsi_ioctl( struct inode *inode, struct file *file, (long *) arg); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!inode->i_rdev) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return revalidate_acsidisk(inode->i_rdev, 1); RO_IOCTLS(inode->i_rdev,arg); default: diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index c0c7762d6c73..5d5ca66dc79d 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -134,15 +134,15 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio) /* stuff timing parameters into controller registers */ driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit; - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ outb_p(regOn, basePort); outReg(param1, regTab[driveNum].reg1); outReg(param2, regTab[driveNum].reg2); outReg(param3, regTab[driveNum].reg3); outReg(param4, regTab[driveNum].reg4); outb_p(regOff, basePort); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } /* @@ -154,8 +154,8 @@ static int findPort (void) byte t; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ for (i = 0; i < ALI_NUM_PORTS; ++i) { basePort = ports[i]; regOff = inb(basePort); @@ -166,7 +166,7 @@ static int findPort (void) dataPort = basePort + 8; t = inReg(0) & 0xf0; outb_p(regOff, basePort); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ if (t != 0x50) return 0; return 1; /* success */ @@ -174,7 +174,7 @@ static int findPort (void) } outb_p(regOff, basePort); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return 0; } @@ -186,15 +186,15 @@ static int initRegisters (void) { byte t; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ outb_p(regOn, basePort); for (p = initData; p->reg != 0; ++p) outReg(p->data, p->reg); outb_p(0x01, regPort); t = inb(regPort) & 0x01; outb_p(regOff, basePort); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return t; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 445e90fca7dc..7a92f74a2c05 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1631,7 +1631,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, return -EFAULT; return 0; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (param > 0xff) return -EINVAL; @@ -1641,7 +1641,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, return put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) param); case BLKFLSBUF: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c index 63b9143b636e..b656a0bd27c3 100644 --- a/drivers/block/dtc2278.c +++ b/drivers/block/dtc2278.c @@ -74,14 +74,14 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (pio >= 3) { - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ /* * This enables PIO mode4 (3?) on the first interface */ sub22(1,0xc3); sub22(0,0xa0); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } else { /* we don't know how to set it back again.. */ } @@ -97,8 +97,8 @@ void init_dtc2278 (void) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* * This enables the second interface */ @@ -114,7 +114,7 @@ void init_dtc2278 (void) sub22(1,0xc3); sub22(0,0xa0); #endif - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ ide_hwifs[0].serialized = 1; ide_hwifs[1].serialized = 1; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 989da1497835..77f0b57651bc 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1825,7 +1825,6 @@ static void floppy_shutdown(void) if (!initialising) show_floppy(); cancel_activity(); - sti(); floppy_enable_hlt(); fd_disable_dma(); @@ -2876,7 +2875,6 @@ static void do_fd_request(void) printk("sect=%ld cmd=%d\n", CURRENT->sector, CURRENT->cmd); return; } - sti(); if (fdc_busy){ /* fdc busy, this new request will be treated when the current one is done */ @@ -3208,7 +3206,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0) return -EINVAL; if (type){ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; LOCK_FDC(drive,1); for (cnt = 0; cnt < N_DRIVE; cnt++){ @@ -3373,7 +3371,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return _COPYOUT(loc); } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(param > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = param; return 0; @@ -3381,7 +3379,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) param); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 558a1b2d2613..52bb33edeb6d 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -603,7 +603,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -616,12 +616,14 @@ static int hd_ioctl(struct inode * inode, struct file * file, return put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); RO_IOCTLS(inode->i_rdev,arg); diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c index b739f39ee4d7..6bf60e4ddc5b 100644 --- a/drivers/block/ht6560b.c +++ b/drivers/block/ht6560b.c @@ -133,8 +133,8 @@ static void ht6560b_selectproc (ide_drive_t *drive) if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - save_flags (flags); - cli(); + __save_flags (flags); /* local CPU only */ + __cli(); /* local CPU only */ (void) inb(HT_SELECT_PORT); (void) inb(HT_SELECT_PORT); (void) inb(HT_SELECT_PORT); @@ -150,7 +150,7 @@ static void ht6560b_selectproc (ide_drive_t *drive) */ outb (timing, IDE_SELECT_REG); (void) inb (IDE_STATUS_REG); - restore_flags (flags); + __restore_flags (flags); /* local CPU only */ #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); #endif diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 661490027563..785fbe1ed9ee 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -415,7 +415,7 @@ struct cdrom_info { /* From Table 124 of the ATAPI 1.2 spec. Unchanged in Table 140 of the ATAPI 2.6 draft standard. */ -const char *sense_key_texts[16] = { +const char * const sense_key_texts[16] = { "No sense data", "Recovered error", "Not ready", @@ -436,9 +436,9 @@ const char *sense_key_texts[16] = { /* From Table 37 of the ATAPI 2.6 draft standard. */ -struct { +const struct { unsigned short packet_command; - const char *text; + const char * const text; } packet_command_texts[] = { { TEST_UNIT_READY, "Test Unit Ready" }, { REQUEST_SENSE, "Request Sense" }, @@ -471,9 +471,9 @@ struct { /* From Table 125 of the ATAPI 1.2 spec., with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ -struct { +const struct { unsigned short asc_ascq; - const char *text; + const char * const text; } sense_data_texts[] = { { 0x0000, "No additional sense information" }, diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 5b46c8302c9d..1ac07f698c4b 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -18,9 +18,10 @@ * Version 1.04 add /proc configurable settings and S.M.A.R.T support * Version 1.05 add capacity support for ATA3 >= 8GB * Version 1.06 get boot-up messages to show full cyl count + * Version 1.07 disable door-locking if it fails */ -#define IDEDISK_VERSION "1.06" +#define IDEDISK_VERSION "1.07" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -185,9 +186,7 @@ static void write_intr (ide_drive_t *drive) } } else error = 1; - out: - if (error) ide_error(drive, "write_intr", stat); } @@ -258,9 +257,7 @@ static void multwrite_intr (ide_drive_t *drive) } } else error = 1; - out: - if (error) ide_error(drive, "multwrite_intr", stat); } @@ -380,7 +377,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl return; } if (!drive->unmask) - __cli(); + __cli(); /* local CPU only */ if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD); @@ -405,7 +402,8 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - (void) ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL); + if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL)) + drive->doorlocking = 0; } return 0; } @@ -414,7 +412,8 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t { if (drive->removable && !drive->usage) { invalidate_buffers(inode->i_rdev); - (void) ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL); + if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL)) + drive->doorlocking = 0; } MOD_DEC_USE_COUNT; } @@ -587,8 +586,13 @@ static int set_multcount(ide_drive_t *drive, int arg) static int set_nowerr(ide_drive_t *drive, int arg) { + unsigned long flags; + + if (ide_spin_wait_hwgroup("set_nowerr", drive, &flags)) + return -EBUSY; drive->nowerr = arg; drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); return 0; } @@ -658,14 +662,12 @@ static void idedisk_setup (ide_drive_t *drive) /* check for removable disks (eg. SYQUEST), ignore 'WD' drives */ if (id->config & (1<<7)) { /* removable disk ? */ - if (id->model[0] != 'W' || id->model[1] != 'D') + if (id->model[0] != 'W' || id->model[1] != 'D') { drive->removable = 1; + drive->doorlocking = 1; + } } - /* SunDisk drives: treat as non-removable; can mess up non-Sun systems! FIXME */ - if (id->model[0] == 'S' && id->model[1] == 'u') - drive->removable = 0; - /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; @@ -714,9 +716,10 @@ static void idedisk_setup (ide_drive_t *drive) if (drive->cyl > drive->bios_cyl) drive->bios_cyl = drive->cyl; } +#if 0 /* done instead for entire identify block in arch/ide.h stuff */ /* fix byte-ordering of buffer size field */ id->buf_size = le16_to_cpu(id->buf_size); - +#endif printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d", drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2, drive->bios_cyl, drive->bios_head, drive->bios_sect); diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 2cbed353922c..c314d1c829b6 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -84,7 +84,7 @@ */ const char *good_dma_drives[] = {"Micropolis 2112A", "CONNER CTMA 4000", - "ST34342A", + "ST34342A", /* for Sun Ultra */ NULL}; /* @@ -128,7 +128,7 @@ void ide_dma_intr (ide_drive_t *drive) } printk("%s: dma_intr: bad DMA status\n", drive->name); } - sti(); + ide__sti(); /* local CPU only */ ide_error(drive, "dma_intr", stat); } @@ -210,7 +210,7 @@ static int config_drive_for_dma (ide_drive_t *drive) struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) { + if (id && (id->capability & 1) && !hwif->no_autodma) { /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) @@ -250,6 +250,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; unsigned int count, reading = 0; + byte dma_stat; switch (func) { case ide_dma_off: @@ -267,22 +268,29 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) return 1; /* try PIO instead of DMA */ outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */ + outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: + /* Note that this is done *after* the cmd has + * been issued to the drive, as per the BM-IDE spec. + * The Promise Ultra33 doesn't work correctly when + * we do this part before issuing the drive cmd. + */ outb(inb(dma_base)|1, dma_base); /* start DMA */ return 0; case ide_dma_end: /* returns 1 on error, 0 otherwise */ - { - byte dma_stat = inb(dma_base+2); - int rc = (dma_stat & 7) != 4; + drive->waiting_for_dma = 0; + dma_stat = inb(dma_base+2); outb(inb(dma_base)&~1, dma_base); /* stop DMA */ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - return rc; /* verify good DMA status */ - } + return (dma_stat & 7) != 4; /* verify good DMA status */ + case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = inb(dma_base+2); + return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -331,9 +339,10 @@ __initfunc(void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigne /* * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: */ -__initfunc(unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_t *hwif, int extra, const char *name)) +__initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)) { - unsigned long dma_base = 0; + unsigned long dma_base = 0; + struct pci_dev *dev = hwif->pci_dev; if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index a4aa0b460e24..e59565e21f80 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -713,7 +713,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) #endif /* IDEFLOPPY_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide_sti(); + ide__sti(); /* local CPU only */ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDEFLOPPY_DEBUG_LOG diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c index 9dd5487f30c9..811b7bed0fb1 100644 --- a/drivers/block/ide-pci.c +++ b/drivers/block/ide-pci.c @@ -43,6 +43,7 @@ #define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) #define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565}) #define DEVID_AEC6210 ((ide_pci_devid_t){0x1191, 0x0005}) +#define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #define IDE_IGNORE ((void *)-1) @@ -71,7 +72,18 @@ extern void ide_init_ns87415(ide_hwif_t *); extern void ide_init_cmd646(ide_hwif_t *); #define INIT_CMD646 &ide_init_cmd646 #else +#ifdef __sparc_v9__ #define INIT_CMD646 IDE_IGNORE +#else +#define INIT_CMD646 NULL +#endif +#endif + +#ifdef CONFIG_BLK_DEV_SL82C105 +extern void ide_init_sl82c105(ide_hwif_t *); +#define INIT_W82C105 &ide_init_sl82c105 +#else +#define INIT_W82C105 IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_RZ1000 @@ -113,6 +125,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, {DEVID_AEC6210, "AEC6210", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }, + {DEVID_W82C105, "W82C105", INIT_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}} }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }}; /* @@ -269,7 +282,7 @@ check_if_enabled: ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ - ctl = dev->base_address[1+2*port] & PCI_BASE_ADDRESS_IO_MASK; + ctl = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK; if (!ctl) ctl = port ? 0x374 : 0x3f4; /* use default value */ base = dev->base_address[2*port] & ~7; @@ -299,7 +312,7 @@ check_if_enabled: if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0; - unsigned long dma_base = ide_get_or_set_dma_base(dev, hwif, extra, d->name); + unsigned long dma_base = ide_get_or_set_dma_base(hwif, extra, d->name); if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { /* * Set up BM-DMA capability (PnP BIOS should have done this) diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index b2ea1bfd96f8..7af146b283ee 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -47,7 +47,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL); ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ - sti(); + ide__sti(); /* local CPU only */ ide_fix_driveid(id); #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) @@ -195,12 +195,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; - save_flags(flags); - cli(); /* some systems need this */ + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only; some systems need this */ do_identify(drive, cmd); /* drive returned ID */ rc = 0; /* drive responded with ID */ (void) GET_STAT(); /* clear drive IRQ */ - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else rc = 2; /* drive refused ID */ if (!HWIF(drive)->irq) { @@ -398,8 +398,8 @@ static void probe_hwif (ide_hwif_t *hwif) return; } - save_flags(flags); - sti(); /* needed for jiffies and irq probing */ + __save_flags(flags); /* local CPU only */ + __sti(); /* local CPU only; needed for jiffies and irq probing */ /* * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. @@ -429,7 +429,7 @@ static void probe_hwif (ide_hwif_t *hwif) } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) { @@ -486,8 +486,8 @@ static int init_irq (ide_hwif_t *hwif) ide_hwgroup_t *hwgroup; ide_hwif_t *match = NULL; - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ hwif->hwgroup = NULL; #if MAX_HWIFS > 1 @@ -499,7 +499,9 @@ static int init_irq (ide_hwif_t *hwif) if (h->hwgroup) { /* scan only initialized hwif's */ if (hwif->irq == h->irq) { hwif->sharing_irq = h->sharing_irq = 1; - save_match(hwif, h, &match); + if (hwif->chipset != ide_pci || h->chipset != ide_pci) { + save_match(hwif, h, &match); + } } if (hwif->serialized) { if (hwif->mate && hwif->mate->irq == h->irq) @@ -520,10 +522,15 @@ static int init_irq (ide_hwif_t *hwif) } else { hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL); memset(hwgroup, 0, sizeof(ide_hwgroup_t)); - hwgroup->hwif = hwif->next = hwif; - hwgroup->rq = NULL; - hwgroup->handler = NULL; - hwgroup->drive = NULL; + hwgroup->hwif = hwif->next = hwif; + hwgroup->rq = NULL; + hwgroup->handler = NULL; + hwgroup->drive = NULL; + hwgroup->busy = 0; + hwgroup->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED; +#if (DEBUG_SPINLOCK > 0) + printk("hwgroup(%s) spinlock is %p\n", hwif->name, &hwgroup->spinlock); /* FIXME */ +#endif init_timer(&hwgroup->timer); hwgroup->timer.function = &ide_timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; @@ -533,10 +540,11 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { - if (ide_request_irq(hwif->irq, &ide_intr, SA_INTERRUPT, hwif->name, hwgroup)) { + int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; + if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 1; } } @@ -558,7 +566,7 @@ static int init_irq (ide_hwif_t *hwif) hwgroup->drive->next = drive; } hwgroup->hwif = HWIF(hwgroup->drive); - restore_flags(flags); /* safe now that hwif->hwgroup is set up */ + restore_flags(flags); /* all CPUs; safe now that hwif->hwgroup is set up */ #ifndef __mc68000__ printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name, @@ -685,13 +693,17 @@ static int hwif_init (ide_hwif_t *hwif) read_ahead[hwif->major] = 8; /* (4kB) */ hwif->present = 1; /* success */ } +#if (DEBUG_SPINLOCK > 0) +{ + static int done = 0; + if (!done++) + printk("io_request_lock is %p\n", &io_request_lock); /* FIXME */ +} +#endif return hwif->present; } - -int ideprobe_init(void); - - +int ideprobe_init (void); static ide_module_t ideprobe_module = { IDE_PROBE_MODULE, ideprobe_init, diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index a86a51fdddb3..26a56e740690 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -111,7 +111,7 @@ static int proc_ide_write_config unsigned long startn = 0, n, flags; const char *start = NULL, *msg = NULL; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Skip over leading whitespace @@ -124,7 +124,7 @@ static int proc_ide_write_config * Do one full pass to verify all parameters, * then do another to actually write the regs. */ - save_flags(flags); + save_flags(flags); /* all CPUs */ do { const char *p; if (for_real) { @@ -133,14 +133,15 @@ static int proc_ide_write_config ide_hwgroup_t *mategroup = NULL; if (hwif->mate && hwif->mate->hwgroup) mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); - cli(); /* ensure all writes are done together */ - while (mygroup->active || (mategroup && mategroup->active)) { - restore_flags(flags); + cli(); /* all CPUs; ensure all writes are done together */ + while (mygroup->busy || (mategroup && mategroup->busy)) { + sti(); /* all CPUs */ if (0 < (signed long)(jiffies - timeout)) { printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name); + restore_flags(flags); /* all CPUs */ return -EBUSY; } - cli(); + cli(); /* all CPUs */ } } p = buffer; @@ -155,7 +156,7 @@ static int proc_ide_write_config break; case 'P': is_pci = 1; #ifdef CONFIG_BLK_DEV_IDEPCI - if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) + if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) break; #endif /* CONFIG_BLK_DEV_IDEPCI */ msg = "not a PCI device"; @@ -174,7 +175,7 @@ static int proc_ide_write_config msg = "bad/missing register number"; goto parse_error; } - if (--n < 0 || *p++ != ':') { + if (n-- == 0 || *p++ != ':') { msg = "missing ':'"; goto parse_error; } @@ -223,7 +224,7 @@ static int proc_ide_write_config break; } if (rc) { - restore_flags(flags); + restore_flags(flags); /* all CPUs */ printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n", msg, dev->bus->number, dev->devfn, reg, val); printk("proc_ide_write_config: error %d\n", rc); @@ -243,10 +244,10 @@ static int proc_ide_write_config } } } while (!for_real++); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ return count; parse_error: - restore_flags(flags); + restore_flags(flags); /* all CPUs */ printk("parse error\n"); return xx_xx_parse_error(start, startn, msg); } @@ -259,27 +260,25 @@ static int proc_ide_read_config #ifdef CONFIG_BLK_DEV_IDEPCI ide_hwif_t *hwif = (ide_hwif_t *)data; - int reg = 0; + struct pci_dev *dev = hwif->pci_dev; + if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) { + int reg = 0; - struct pci_dev *dev = hwif->pci_dev; - - out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", - dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); - do { - byte val; - int rc = pci_read_config_byte(dev, reg, &val); - if (rc) { - printk("proc_ide_read_config: error reading bus %02x dev %02x reg 0x%02x\n", - dev->bus->number, dev->devfn, reg); - printk("proc_ide_read_config: error %d\n", rc); - return -EIO; - out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); - } else - out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); - } while (reg < 0x100); -#else /* CONFIG_BLK_DEV_IDEPCI */ - out += sprintf(out, "(none)\n"); + out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", + dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); + do { + byte val; + int rc = pci_read_config_byte(dev, reg, &val); + if (rc) { + printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n", + rc, dev->bus->number, dev->devfn, reg); + out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); + } else + out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); + } while (reg < 0x100); + } else #endif /* CONFIG_BLK_DEV_IDEPCI */ + out += sprintf(out, "(none)\n"); len = out - page; PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -425,14 +424,13 @@ static int proc_ide_write_settings (struct file *file, const char *buffer, unsigned long count, void *data) { ide_drive_t *drive = (ide_drive_t *) data; - ide_hwif_t *hwif = HWIF(drive); char name[MAX_LEN + 1]; int for_real = 0, len; - unsigned long n, flags; + unsigned long n; const char *start = NULL; ide_settings_t *setting; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Skip over leading whitespace @@ -443,27 +441,10 @@ static int proc_ide_write_settings } /* * Do one full pass to verify all parameters, - * then do another to actually write the pci regs. + * then do another to actually write the new settings. */ - save_flags(flags); do { const char *p; - if (for_real) { - unsigned long timeout = jiffies + (3 * HZ); - ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); - ide_hwgroup_t *mategroup = NULL; - if (hwif->mate && hwif->mate->hwgroup) - mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); - cli(); /* ensure all writes are done together */ - while (mygroup->active || (mategroup && mategroup->active)) { - restore_flags(flags); - if (0 < (signed long)(jiffies - timeout)) { - printk("/proc/ide/%s/settings: channel(s) busy, cannot write\n", drive->name); - return -EBUSY; - } - cli(); - } - } p = buffer; n = count; while (n > 0) { @@ -508,10 +489,8 @@ static int proc_ide_write_settings ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); } } while (!for_real++); - restore_flags(flags); return count; parse_error: - restore_flags(flags); printk("proc_ide_write_settings(): parse error\n"); return -EINVAL; } @@ -573,7 +552,7 @@ static int proc_ide_write_driver { ide_drive_t *drive = (ide_drive_t *) data; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (ide_replace_subdriver(drive, buffer)) return -EINVAL; diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index c4f5c6e2396d..3b6e2790ff45 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1432,8 +1432,8 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_add_stage_tail\n"); #endif /* IDETAPE_DEBUG_LOG */ - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ stage->next=NULL; if (tape->last_stage != NULL) tape->last_stage->next=stage; @@ -1444,7 +1444,7 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) tape->next_stage=tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } /* @@ -1754,7 +1754,7 @@ static void idetape_pc_intr (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide_sti(); + ide__sti(); /* local CPU only */ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDETAPE_DEBUG_LOG @@ -2398,11 +2398,11 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) */ return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh)); } - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (tape->active_stage == tape->first_stage) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ rq_ptr = &tape->first_stage->rq; bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); @@ -2451,13 +2451,13 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) * Pay special attention to possible race conditions. */ while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) { - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (idetape_pipeline_active (tape)) { idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } else { - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ idetape_insert_pipeline_into_queue (drive); if (idetape_pipeline_active (tape)) continue; @@ -2514,12 +2514,12 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive) if (tape->first_stage == NULL) return; - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ tape->next_stage = NULL; if (idetape_pipeline_active (tape)) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ while (tape->first_stage != NULL) idetape_remove_stage_head (drive); @@ -2539,8 +2539,8 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive) if (!idetape_pipeline_active (tape)) idetape_insert_pipeline_into_queue (drive); - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (!idetape_pipeline_active (tape)) goto abort; #if IDETAPE_DEBUG_BUGS @@ -2550,7 +2550,7 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_BUGS */ idetape_wait_for_request (&tape->last_stage->rq); abort: - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ } static void idetape_pad_zeros (ide_drive_t *drive, int bcount) @@ -2795,11 +2795,11 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c * Wait until the first read-ahead request * is serviced. */ - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (tape->active_stage == tape->first_stage) idetape_wait_for_request (tape->active_data_request); - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) count++; @@ -3620,14 +3620,14 @@ static int idetape_cleanup (ide_drive_t *drive) int minor = tape->minor; unsigned long flags; - save_flags (flags); - cli (); + save_flags (flags); /* all CPUs (overkill?) */ + cli(); /* all CPUs (overkill?) */ if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) { - restore_flags(flags); + restore_flags(flags); /* all CPUs (overkill?) */ return 1; } idetape_chrdevs[minor].drive = NULL; - restore_flags (flags); + restore_flags (flags); /* all CPUs (overkill?) */ DRIVER(drive)->busy = 0; (void) ide_unregister_subdriver (drive); drive->driver_data = NULL; diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 111186eba2c4..191678d77467 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -86,6 +86,9 @@ * Version 6.12 integrate ioctl and proc interfaces * fix parsing of "idex=" command line parameter * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com + * Version 6.14 fixed IRQ sharing among PCI devices + * Version 6.15 added SMP awareness to IDE drivers + * Version 6.16 fixed various bugs; even more SMP friendly * * Some additional driver compile-time options are in ide.h * @@ -155,13 +158,13 @@ static unsigned long read_timer(void) unsigned long t, flags; int i; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ return (t - i); } #endif /* DISK_RECOVERY_TIME */ @@ -178,15 +181,11 @@ static inline void set_recovery_timer (ide_hwif_t *hwif) */ static void init_hwif_data (unsigned int index) { - byte *p; unsigned int unit; ide_hwif_t *hwif = &ide_hwifs[index]; /* bulk initialize hwif & drive info with zeros */ - p = ((byte *) hwif) + sizeof(ide_hwif_t); - do { - *--p = 0; - } while (p > (byte *) hwif); + memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ hwif->index = index; @@ -299,11 +298,11 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ do_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -332,11 +331,11 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); - __cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ do_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -391,6 +390,85 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); } +/* + * Needed for PCI irq sharing + */ +static inline int drive_is_ready (ide_drive_t *drive) +{ + if (drive->waiting_for_dma) + return HWIF(drive)->dmaproc(ide_dma_test_irq, drive); +#if 0 + udelay(1); /* need to guarantee 400ns since last command was issued */ +#endif + if (GET_STAT() & BUSY_STAT) + return 0; /* drive busy: definitely not interrupting */ + return 1; /* drive ready: *might* be interrupting */ +} + +#if !defined(__SMP__) && defined(DEBUG_SPINLOCKS) && (DEBUG_SPINLOCKS > 1) + +static const char *ide_lock_name(spinlock_t *spinlock) +{ + int index; + + if (spinlock == &io_request_lock) + return "io_request_lock"; + for (index = 0; index < MAX_HWIFS; index++) { + ide_hwif_t *hwif = &ide_hwifs[index]; + ide_hwgroup_t *hwgroup = hwif->hwgroup; + if (spinlock == &hwgroup->spinlock) + return hwif->name; + } + return "?"; +} + +#define IDE_SPIN_LOCK_IRQ(msg,spinlock) \ +{ \ + static int __babble = 20; \ + __cli(); \ + if ((spinlock)->lock && __babble) { \ + __babble--; \ + printk("ide_lock: %s: already locked (%s)\n", msg, ide_lock_name(spinlock)); \ + } \ + /* spin_lock_irq(spinlock); */ \ + (spinlock)->lock = 1; \ +} + +#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags) \ +{ \ + __save_flags(flags); \ + IDE_SPIN_LOCK_IRQ(msg,spinlock); \ +} + +#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags) \ +{ \ + static int __babble = 20; \ + __cli(); \ + if (!((spinlock)->lock) && __babble) { \ + __babble--; \ + printk("ide_unlock: %s: not locked (%s)\n", msg, ide_lock_name(spinlock)); \ + } \ + /* spin_unlock_irqrestore(msg,spinlock,flags); */ \ + (spinlock)->lock = 0; \ + restore_flags(flags); \ +} + +#define IDE_SPIN_UNLOCK(msg,spinlock) \ +{ \ + unsigned long __flags; \ + __save_flags(__flags); \ + IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,__flags); \ +} + +#else /* DEBUG_SPINLOCKS */ + +#define IDE_SPIN_LOCK_IRQ(msg,spinlock) spin_lock_irq(spinlock) +#define IDE_SPIN_LOCK_IRQSAVE(msg,spinlock,flags) spin_lock_irqsave(spinlock,flags) +#define IDE_SPIN_UNLOCK(msg,spinlock) spin_unlock(spinlock) +#define IDE_SPIN_UNLOCK_IRQRESTORE(msg,spinlock,flags) spin_unlock_irqrestore(spinlock,flags) + +#endif /* DEBUG_SPINLOCKS */ + /* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points @@ -400,7 +478,10 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun */ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout) { + unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); + + IDE_SPIN_LOCK_IRQSAVE("ide_set_handler", &hwgroup->spinlock, flags); #ifdef DEBUG if (hwgroup->handler != NULL) { printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", @@ -410,6 +491,7 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int t hwgroup->handler = handler; hwgroup->timer.expires = jiffies + timeout; add_timer(&(hwgroup->timer)); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_set_handler", &hwgroup->spinlock, flags); } /* @@ -558,8 +640,8 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - __save_flags(flags); - __cli(); /* Why ? */ + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -569,7 +651,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ return; } @@ -597,7 +679,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ } /* @@ -625,15 +707,17 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) args[2] = IN_BYTE(IDE_NSECTOR_REG); } } - __save_flags(flags); - __cli(); + IDE_SPIN_LOCK_IRQSAVE("ide_end_drive_cmd", &io_request_lock, flags); drive->queue = rq->next; blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_end_drive_cmd", &io_request_lock, flags); + save_flags(flags); /* all CPUs; overkill? */ + cli(); /* all CPUs; overkill? */ if (rq->sem != NULL) - up(rq->sem); - __restore_flags(flags); + up(rq->sem); /* inform originator that rq has been serviced */ + restore_flags(flags); /* all CPUs; overkill? */ } /* @@ -644,8 +728,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) unsigned long flags; byte err = 0; - __save_flags (flags); - /* ide_sti(); HACK */ + __save_flags (flags); /* local CPU only */ + ide__sti(); /* local CPU only */ printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -698,7 +782,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - __restore_flags (flags); + __restore_flags (flags); /* local CPU only */ return err; } @@ -732,7 +816,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) byte err; err = ide_dump_status(drive, msg, stat); - if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return; /* retry only "normal" I/O: */ if (rq->cmd == IDE_DRIVE_CMD) { @@ -784,7 +868,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { ide_set_handler (drive, handler, WAIT_CMD); - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); OUT_BYTE(cmd,IDE_COMMAND_REG); } @@ -799,7 +883,7 @@ static void drive_cmd_intr (ide_drive_t *drive) byte stat = GET_STAT(); int retries = 10; - /* ide_sti(); HACK */ + ide__sti(); /* local CPU only */ if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; @@ -857,17 +941,17 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); - /* ide_sti(); HACK */ + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only */ timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ ide_error(drive, "status timeout", stat); return 1; } } - __restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } udelay(1); /* allow status to settle, then read it again */ if (OK_STAT((stat = GET_STAT()), good, bad)) @@ -909,17 +993,18 @@ static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) } /* - * do_request() initiates handling of a new I/O request + * start_request() initiates handling of a new I/O request */ -static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_drive_t *drive) +static inline void start_request (ide_drive_t *drive) { unsigned long block, blockend; struct request *rq = drive->queue; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; + ide_hwif_t *hwif = HWIF(drive); - /* ide_sti(); HACK */ + ide__sti(); /* local CPU only */ #ifdef DEBUG - printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); + printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif if (unit >= MAX_DRIVES) { printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev)); @@ -946,15 +1031,11 @@ static inline void do_request (ide_hwgroup_t *hwgroup, ide_hwif_t *hwif, ide_dri #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); #endif - - hwgroup->hwif = hwif; - hwgroup->drive = drive; SELECT_DRIVE(hwif, drive); if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); return; } - if (!drive->special.all) { if (rq->cmd == IDE_DRIVE_CMD) { execute_drive_cmd(drive, rq); @@ -973,7 +1054,7 @@ kill_rq: if (drive->driver != NULL) DRIVER(drive)->end_request(0, HWGROUP(drive)); else - ide_end_request(0, hwgroup); + ide_end_request(0, HWGROUP(drive)); } /* @@ -1000,21 +1081,19 @@ repeat: best = NULL; drive = hwgroup->drive; do { - if (!drive->queue) - continue; - if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies)) - continue; - if (!best) { - best = drive; - continue; + if (drive->queue && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { + if (!best + || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) + || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) + { + struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major]; + if (bdev->current_request != &bdev->plug) + best = drive; + } } - if (drive->sleep && (!best->sleep || drive->sleep < best->sleep)) - best = drive; - if (!best->sleep && WAKEUP(drive) < WAKEUP(best)) - best = drive; } while ((drive = drive->next) != hwgroup->drive); - if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) { - long t = (signed) (WAKEUP(best) - jiffies); /* BUGGY? */ + if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { + long t = (signed long)(WAKEUP(best) - jiffies); if (t >= WAIT_MIN_SLEEP) { /* * We *may* have some time to spare, but first let's see if @@ -1022,9 +1101,10 @@ repeat: */ drive = best->next; do { - if (drive->sleep) /* this drive tried to be nice to us */ - continue; - if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) { /* BUGGY? */ + if (!drive->sleep + && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) + && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) + { ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); goto repeat; } @@ -1034,33 +1114,6 @@ repeat: return best; } -static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup) -{ - ide_drive_t *drive = hwgroup->drive; - unsigned long sleep = 0; - - hwgroup->rq = NULL; - do { - blk_dev[HWIF(drive)->major].current_request = NULL; - if (!drive->sleep) - continue; - if (!sleep) { - sleep = drive->sleep; - continue; - } - if (drive->sleep < sleep) - sleep = drive->sleep; - } while ((drive = drive->next) != hwgroup->drive); - if (sleep) { - if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) - sleep = jiffies + WAIT_MIN_SLEEP; - hwgroup->timer.expires = sleep; - add_timer(&hwgroup->timer); - } else /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */ - ide_release_lock(&ide_lock); - hwgroup->active = 0; -} - /* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is always masked before entry, and @@ -1075,30 +1128,68 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup) * tolerance for latency during I/O. For devices which don't suffer from * this problem (most don't), the unmask flag can be set using the "hdparm" * utility, to permit other interrupts during data/cmd transfers. + * + * Caller must have already acquired spinlock using *spinflags + * */ -void ide_do_request (ide_hwgroup_t *hwgroup) +static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq) { - __cli(); /* paranoia */ - if (hwgroup->handler != NULL) { - printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); - return; - } - do { - ide_drive_t *drive = choose_drive(hwgroup); - if (drive != NULL) { - ide_hwif_t *hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) - OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); - drive->sleep = 0; - blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue; - drive->service_start = jiffies; - do_request(hwgroup, hwif, drive); - __cli(); - } else { - ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */ + struct blk_dev_struct *bdev; + ide_drive_t *drive; + ide_hwif_t *hwif; + unsigned long io_flags; + + hwgroup->busy = 1; + while (hwgroup->handler == NULL) { + IDE_SPIN_LOCK_IRQSAVE("ide_do_request1", &io_request_lock, io_flags); + drive = choose_drive(hwgroup); + if (drive == NULL) { + unsigned long sleep = 0; + + hwgroup->rq = NULL; + drive = hwgroup->drive; + do { + bdev = &blk_dev[HWIF(drive)->major]; + if (bdev->current_request != &bdev->plug) /* FIXME: this will do for now */ + bdev->current_request = NULL; /* (broken since patch-2.1.15) */ + if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) + sleep = drive->sleep; + } while ((drive = drive->next) != hwgroup->drive); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request2", &io_request_lock, io_flags); + if (sleep) { + if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) + sleep = jiffies + WAIT_MIN_SLEEP; + hwgroup->timer.expires = sleep; + add_timer(&hwgroup->timer); + } else { + /* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */ + ide_release_lock(&ide_lock); /* for atari only */ + } + hwgroup->busy = 0; return; } - } while (hwgroup->handler == NULL); + hwif = HWIF(drive); + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) /* set nIEN for previous hwif */ + OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]); + hwgroup->hwif = hwif; + hwgroup->drive = drive; + drive->sleep = 0; + drive->service_start = jiffies; + + bdev = &blk_dev[hwif->major]; + if (bdev->current_request == &bdev->plug) /* FIXME: paranoia */ + printk("%s: Huh? nuking plugged queue\n", drive->name); + bdev->current_request = hwgroup->rq = drive->queue; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request3", &io_request_lock, io_flags); + + if (hwif->irq != masked_irq) + disable_irq(hwif->irq); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_request4", &hwgroup->spinlock, *hwgroup_flags); + start_request(drive); + IDE_SPIN_LOCK_IRQSAVE("ide_do_request5", &hwgroup->spinlock, *hwgroup_flags); + if (hwif->irq != masked_irq) + enable_irq(hwif->irq); + } } /* @@ -1106,100 +1197,136 @@ void ide_do_request (ide_hwgroup_t *hwgroup) */ struct request **ide_get_queue (kdev_t dev) { - struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); - ide_hwif_t *hwif = bdev->data; + ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data; return &hwif->drives[DEVICE_NR(dev) & 1].queue; } /* - * do_hwgroup_request() invokes ide_do_request() after first masking - * all possible interrupts for the current hwgroup. This prevents race - * conditions in the event that an unexpected interrupt occurs while - * we are in the driver. - * - * Note that the io-request lock will guarantee that the driver never gets - * re-entered even on another interrupt level, so we no longer need to - * mask the irq's. + * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy. */ -static void do_hwgroup_request (ide_hwgroup_t *hwgroup) +static void do_hwgroup_request (const char *msg, ide_hwgroup_t *hwgroup) { - if (hwgroup->handler == NULL) { - del_timer(&hwgroup->timer); - ide_get_lock(&ide_lock, ide_intr, hwgroup); - hwgroup->active = 1; - ide_do_request (hwgroup); + unsigned long flags; + + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, flags); + if (hwgroup->busy) { + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags); + return; } + del_timer(&hwgroup->timer); + ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only */ + ide_do_request(hwgroup, &flags, 0); + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, flags); +} + +/* + * As of linux-2.1.95, ll_rw_blk.c invokes our do_idex_request() + * functions with the io_request_spinlock already grabbed. + * Since we need to do our own spinlock's internally, + * on paths that don't necessarily originate through the + * do_idex_request() path. + * + * We have to undo the spinlock on entry, and restore it again on exit. + * Fortunately, this is mostly a nop for non-SMP kernels. + */ +static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup) +{ + IDE_SPIN_UNLOCK("unlock_do_hwgroup_request", &io_request_lock); + do_hwgroup_request ("from unlock_do_hwgroup_request", hwgroup); + IDE_SPIN_LOCK_IRQ("unlock_do_hwgroup_request", &io_request_lock); } -void do_ide0_request (void) /* invoked with __cli() */ +void do_ide0_request (void) { - do_hwgroup_request (ide_hwifs[0].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[0].hwgroup); } #if MAX_HWIFS > 1 -void do_ide1_request (void) /* invoked with __cli() */ +void do_ide1_request (void) { - do_hwgroup_request (ide_hwifs[1].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[1].hwgroup); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) /* invoked with __cli() */ +void do_ide2_request (void) { - do_hwgroup_request (ide_hwifs[2].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[2].hwgroup); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) /* invoked with __cli() */ +void do_ide3_request (void) { - do_hwgroup_request (ide_hwifs[3].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[3].hwgroup); } #endif /* MAX_HWIFS > 3 */ #if MAX_HWIFS > 4 -void do_ide4_request (void) /* invoked with cli() */ +void do_ide4_request (void) { - do_hwgroup_request (ide_hwifs[4].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[4].hwgroup); } #endif /* MAX_HWIFS > 4 */ #if MAX_HWIFS > 5 -void do_ide5_request (void) /* invoked with cli() */ +void do_ide5_request (void) { - do_hwgroup_request (ide_hwifs[5].hwgroup); + unlock_do_hwgroup_request (ide_hwifs[5].hwgroup); } #endif /* MAX_HWIFS > 5 */ +static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq) +{ + unsigned long flags; + ide_drive_t *drive; + + IDE_SPIN_LOCK_IRQSAVE("start_next_request", &hwgroup->spinlock, flags); + if (hwgroup->handler != NULL) { + IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags); + return; + } + drive = hwgroup->drive; + set_recovery_timer(HWIF(drive)); + drive->service_time = jiffies - drive->service_start; + ide_do_request(hwgroup, &flags, masked_irq); + IDE_SPIN_UNLOCK_IRQRESTORE("start_next_request", &hwgroup->spinlock, flags); +} + void ide_timer_expiry (unsigned long data) { ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; - ide_drive_t *drive = hwgroup->drive; + ide_drive_t *drive; ide_handler_t *handler; unsigned long flags; - __save_flags(flags); - __cli(); - - if ((handler = hwgroup->handler) != NULL) { - hwgroup->handler = NULL; - if (hwgroup->poll_timeout != 0) /* polling in progress? */ - handler(drive); - else { /* abort the operation */ - if (hwgroup->hwif->dmaproc) - (void) hwgroup->hwif->dmaproc (ide_dma_end, drive); - ide_error(drive, "irq timeout", GET_STAT()); - } - __cli(); - if (hwgroup->handler == NULL) { - set_recovery_timer(HWIF(drive)); - drive->service_time = jiffies - drive->service_start; - do_hwgroup_request (hwgroup); + IDE_SPIN_LOCK_IRQSAVE("ide_timer_expiry1", &hwgroup->spinlock, flags); + drive = hwgroup->drive; + if ((handler = hwgroup->handler) == NULL) { + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry2", &hwgroup->spinlock, flags); + do_hwgroup_request("timer do_hwgroup_request", hwgroup); + return; + } + hwgroup->busy = 1; /* should already be "1" */ + hwgroup->handler = NULL; + if (hwgroup->poll_timeout != 0) { /* polling in progress? */ + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry3", &hwgroup->spinlock, flags); + handler(drive); + } else if (drive_is_ready(drive)) { + printk("%s: lost interrupt\n", drive->name); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry4", &hwgroup->spinlock, flags); + handler(drive); + } else { + if (drive->waiting_for_dma) { + (void) hwgroup->hwif->dmaproc(ide_dma_end, drive); + printk("%s: timeout waiting for DMA\n", drive->name); } - } else - do_hwgroup_request (hwgroup); - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry5", &hwgroup->spinlock, flags); + ide_error(drive, "irq timeout", GET_STAT()); + } + del_timer(&hwgroup->timer); + start_next_request(hwgroup, 0); } /* @@ -1238,75 +1365,78 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { /* Try to not flood the console with msgs */ - static unsigned long last_msgtime = 0; + static unsigned long last_msgtime = 0, count = 0; + ++count; if (0 < (signed long)(jiffies - (last_msgtime + HZ))) { last_msgtime = jiffies; - printk("%s%s: unexpected interrupt, status=0x%02x\n", - hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat); + printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n", + hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count); } } } } while ((hwif = hwif->next) != hwgroup->hwif); } - -#ifdef __sparc_v9__ -#define IDE_IRQ_EQUAL(irq1, irq2) (1) -#else -#define IDE_IRQ_EQUAL(irq1, irq2) ((irq1) == (irq2)) -#endif - -static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs) -{ - ide_hwgroup_t *hwgroup = dev_id; - ide_hwif_t *hwif = hwgroup->hwif; - ide_handler_t *handler; - - if (!ide_ack_intr (hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET])) - return; - - if (IDE_IRQ_EQUAL(irq, hwif->irq) - && (handler = hwgroup->handler) != NULL) { - ide_drive_t *drive = hwgroup->drive; -#if 1 /* temporary, remove later -- FIXME */ - { - struct request *rq = hwgroup->rq; - if (rq != NULL - &&( MAJOR(rq->rq_dev) != HWIF(drive)->major - || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit)) - { - printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n"); - return; - } - } -#endif /* temporary */ - hwgroup->handler = NULL; - del_timer(&(hwgroup->timer)); - /* if (drive->unmask) - ide_sti(); HACK */ - handler(drive); - /* this is necessary, as next rq may be different irq */ - if (hwgroup->handler == NULL) { - set_recovery_timer(HWIF(drive)); - drive->service_time = jiffies - drive->service_start; - ide_do_request(hwgroup); - } - } else { - unexpected_intr(irq, hwgroup); - } - __cli(); - hwif = hwgroup->hwif; -} - /* * entry point for all interrupts, caller does __cli() for us */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; + ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; + ide_hwif_t *hwif; + ide_drive_t *drive; + ide_handler_t *handler; - spin_lock_irqsave(&io_request_lock, flags); - do_ide_intr(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + __cli(); /* local CPU only */ + IDE_SPIN_LOCK_IRQSAVE("ide_intr1", &hwgroup->spinlock, flags); + hwif = hwgroup->hwif; + if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { + /* + * Not expecting an interrupt from this drive. + * That means this could be: + * (1) an interrupt from another PCI device + * sharing the same PCI INT# as us. + * or (2) a drive just entered sleep or standby mode, + * and is interrupting to let us know. + * or (3) a spurious interrupt of unknown origin. + * + * For PCI, we cannot tell the difference, + * so in that case we just ignore it and hope it goes away. + */ +#ifdef CONFIG_BLK_DEV_IDEPCI + if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) +#endif /* CONFIG_BLK_DEV_IDEPCI */ + { + /* + * Probably not a shared PCI interrupt, + * so we can safely try to do something about it: + */ + (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); + unexpected_intr(irq, hwgroup); + } + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr2", &hwgroup->spinlock, flags); + return; + } + drive = hwgroup->drive; + if (!drive || !drive_is_ready(drive)) { + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr3", &hwgroup->spinlock, flags); + return; + } + hwgroup->handler = NULL; + (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); + del_timer(&(hwgroup->timer)); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_intr4", &hwgroup->spinlock, flags); + if (drive->unmask) + ide__sti(); /* local CPU only */ + handler(drive); /* service this interrupt, may set handler for next interrupt */ + /* + * Note that handler() may have set things up for another + * interrupt to occur soon, but it cannot happen until + * we exit from this routine, because it will be the + * same irq as is currently being serviced here, + * and Linux won't allow another (on any CPU) until we return. + */ + start_next_request(hwgroup, hwif->irq); } /* @@ -1390,10 +1520,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio if (action == ide_wait) rq->sem = &sem; - __save_flags(flags); - __cli(); + IDE_SPIN_LOCK_IRQSAVE("ide_do_drive_cmd", &io_request_lock, flags); cur_rq = drive->queue; - if (cur_rq == NULL || action == ide_preempt) { rq->next = cur_rq; drive->queue = rq; @@ -1407,13 +1535,13 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio rq->next = cur_rq->next; cur_rq->next = rq; } - if (!hwgroup->active) { - do_hwgroup_request(hwgroup); - __cli(); - } - if (action == ide_wait && rq->rq_status != RQ_INACTIVE) + IDE_SPIN_UNLOCK_IRQRESTORE("ide_do_drive_cmd", &io_request_lock, flags); + do_hwgroup_request("drive_cmd do_hwgroup_request", hwgroup); + save_flags(flags); /* all CPUs; overkill? */ + cli(); /* all CPUs; overkill? */ + if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ - __restore_flags(flags); + restore_flags(flags); /* all CPUs; overkill? */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -1428,6 +1556,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio int ide_revalidate_disk(kdev_t i_rdev) { ide_drive_t *drive; + ide_hwgroup_t *hwgroup; unsigned int p, major, minor; long flags; @@ -1435,15 +1564,15 @@ int ide_revalidate_disk(kdev_t i_rdev) return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; - __save_flags(flags); - __cli(); + hwgroup = HWGROUP(drive); + IDE_SPIN_LOCK_IRQSAVE("ide_revalidate_disk", &hwgroup->spinlock, flags); if (drive->busy || (drive->usage > 1)) { - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; - __restore_flags(flags); + IDE_SPIN_UNLOCK_IRQRESTORE("ide_revalidate_disk", &hwgroup->spinlock, flags); for (p = 0; p < (1<part[p].nr_sects > 0) { @@ -1589,8 +1718,8 @@ void ide_unregister (unsigned int index) if (index >= MAX_HWIFS) return; - __save_flags(flags); - __cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; @@ -1680,7 +1809,7 @@ void ide_unregister (unsigned int index) } init_hwif_data (index); /* restore hwif data to pristine status */ abort: - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ } int ide_register (int arg1, int arg2, int irq) @@ -1719,7 +1848,7 @@ found: return hwif->present ? index : -1; } -void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) +void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; @@ -1798,38 +1927,63 @@ repeat: int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) { - if (!(setting->rw & SETTING_READ)) - return -EINVAL; - switch(setting->data_type) { - case TYPE_BYTE: - return *((u8 *) setting->data); - case TYPE_SHORT: - return *((u16 *) setting->data); - case TYPE_INT: - case TYPE_INTA: - return *((u32 *) setting->data); - default: - return -EINVAL; + int val = -EINVAL; + unsigned long flags; + + if ((setting->rw & SETTING_READ)) { + IDE_SPIN_LOCK_IRQSAVE("ide_read_setting", &HWGROUP(drive)->spinlock, flags); + switch(setting->data_type) { + case TYPE_BYTE: + val = *((u8 *) setting->data); + break; + case TYPE_SHORT: + val = *((u16 *) setting->data); + break; + case TYPE_INT: + case TYPE_INTA: + val = *((u32 *) setting->data); + break; + } + IDE_SPIN_UNLOCK_IRQRESTORE("ide_read_setting", &HWGROUP(drive)->spinlock, flags); + } + return val; +} + +int ide_spin_wait_hwgroup (const char *msg, ide_drive_t *drive, unsigned long *flags) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long timeout = jiffies + (3 * HZ); + + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags); + while (hwgroup->busy) { + IDE_SPIN_UNLOCK_IRQRESTORE(msg, &hwgroup->spinlock, *flags); + __sti(); /* local CPU only; needed for jiffies */ + if (0 < (signed long)(jiffies - timeout)) { + printk("%s: %s: channel busy\n", drive->name, msg); + return -EBUSY; + } + IDE_SPIN_LOCK_IRQSAVE(msg, &hwgroup->spinlock, *flags); } + return 0; } int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) { unsigned long flags; - int i, rc = 0; + int i; u32 *p; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!(setting->rw & SETTING_WRITE)) return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; - __save_flags(flags); - __cli(); if (setting->set) - rc = setting->set(drive, val); - else switch (setting->data_type) { + return setting->set(drive, val); + if (ide_spin_wait_hwgroup("ide_write_settings", drive, &flags)) + return -EBUSY; + switch (setting->data_type) { case TYPE_BYTE: *((u8 *) setting->data) = val; break; @@ -1845,8 +1999,8 @@ int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) *p = val; break; } - __restore_flags(flags); - return rc; + IDE_SPIN_UNLOCK_IRQRESTORE("ide_write_setting4", &HWGROUP(drive)->spinlock, flags); + return 0; } static int set_io_32bit(ide_drive_t *drive, int arg) @@ -1956,7 +2110,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, return 0; } case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; @@ -1965,21 +2119,17 @@ static int ide_ioctl (struct inode *inode, struct file *file, return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); case BLKRRPART: /* Re-read partition tables */ - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; return ide_revalidate_disk(inode->i_rdev); + case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id == NULL) return -ENOMSG; -#if 0 - if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id))) + if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; -#else - if (copy_to_user((char *)arg, (char *)drive->id, 142)) - return -EFAULT; -#endif return 0; case HDIO_GET_NICE: @@ -1993,7 +2143,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, { byte args[4], *argbuf = args; int argsize = 4; - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (NULL == (void *) arg) return ide_do_drive_cmd(drive, &rq, ide_wait); if (copy_from_user(args, (void *)arg, 4)) @@ -2016,7 +2166,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_SCAN_HWIF: { int args[3]; - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (copy_from_user(args, (void *)arg, 3 * sizeof(int))) return -EFAULT; if (ide_register(args[0], args[1], args[2]) == -1) @@ -2024,7 +2174,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, return 0; } case HDIO_SET_NICE: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (drive->driver == NULL) return -EPERM; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) @@ -2311,7 +2461,7 @@ __initfunc(void ide_setup (char *s)) goto bad_option; /* chipset already specified */ if (i <= -7 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ - if (ide_hwifs[hw^1].chipset != ide_unknown) + if (i <= -7 && ide_hwifs[hw^1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } @@ -2528,12 +2678,6 @@ __initfunc(static void probe_for_hwifs (void)) ide_probe_for_rz100x(); } #endif /* CONFIG_BLK_DEV_RZ1000 */ -#ifdef CONFIG_BLK_DEV_SL82C105 - { - extern void ide_probe_for_sl82c105(void); - ide_probe_for_sl82c105(); - } -#endif /* CONFIG_BLK_DEV_SL82C105 */ #endif /* CONFIG_BLK_DEV_IDEPCI */ } #endif /* CONFIG_PCI */ @@ -2560,21 +2704,21 @@ __initfunc(void ide_init_builtin_drivers (void)) probe_for_hwifs (); #ifdef CONFIG_BLK_DEV_IDE -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { - ide_get_lock(&ide_lock, NULL, NULL); + ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ disable_irq(ide_hwifs[0].irq); } -#endif /* __mc68000__ */ +#endif /* __mc68000__ || CONFIG_APUS */ (void) ideprobe_init(); -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { enable_irq(ide_hwifs[0].irq); - ide_release_lock(&ide_lock); + ide_release_lock(&ide_lock); /* for atari only */ } -#endif /* __mc68000__ */ +#endif /* __mc68000__ || CONFIG_APUS */ #endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_PROC_FS @@ -2705,16 +2849,15 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio { unsigned long flags; - __save_flags(flags); - __cli(); - if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || - drive->busy || drive->usage) { - __restore_flags(flags); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) { + restore_flags(flags); /* all CPUs */ return 1; } drive->driver = driver; setup_driver_defaults(drive); - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ if (drive->autotune != 2) { if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); @@ -2733,10 +2876,10 @@ int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; - __save_flags(flags); - __cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 1; } #ifdef CONFIG_PROC_FS @@ -2745,7 +2888,7 @@ int ide_unregister_subdriver (ide_drive_t *drive) #endif auto_remove_settings(drive); drive->driver = NULL; - __restore_flags(flags); + restore_flags(flags); /* all CPUs */ return 0; } diff --git a/drivers/block/ide.h b/drivers/block/ide.h index 565ffea7dc07..24002dd4eec1 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -204,26 +204,28 @@ typedef struct ide_drive_s { unsigned long service_start; /* time we started last request */ unsigned long service_time; /* service time of last request */ special_t special; /* special action flags */ + byte keep_settings; /* restore settings after drive reset */ + byte using_dma; /* disk is using dma for read/write */ + byte waiting_for_dma; /* dma currently in progress */ + byte unmask; /* flag: okay to unmask other irqs */ + byte slow; /* flag: slow data port */ + byte bswap; /* flag: byte swap data */ + byte dsc_overlap; /* flag: DSC overlap */ + byte nice1; /* flag: give potential excess bandwidth */ unsigned present : 1; /* drive is physically present */ unsigned noprobe : 1; /* from: hdx=noprobe */ - byte keep_settings; /* restore settings after drive reset */ unsigned busy : 1; /* currently doing revalidate_disk() */ unsigned removable : 1; /* 1 if need to do check_media_change */ - byte using_dma; /* disk is using dma for read/write */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - byte unmask; /* flag: okay to unmask other irqs */ unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ - byte slow; /* flag: slow data port */ - unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned revalidate : 1; /* request revalidation */ - byte bswap; /* flag: byte swap data */ - byte dsc_overlap; /* flag: DSC overlap */ unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - byte nice1; /* flag: give potential excess bandwidth */ unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ + unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */ + unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ #if FAKE_FDISK_FOR_EZDRIVE unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ #endif /* FAKE_FDISK_FOR_EZDRIVE */ @@ -270,7 +272,8 @@ typedef struct ide_drive_s { * should either try again later, or revert to PIO for the current request. */ typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, - ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly + ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly, + ide_dma_test_irq } ide_dma_action_t; typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); @@ -340,7 +343,7 @@ typedef struct hwif_s { unsigned reset : 1; /* reset after probe */ unsigned no_autodma : 1; /* don't automatically enable DMA at boot */ byte channel; /* for dual-port chips: 0=primary, 1=secondary */ - struct pci_dev *pci_dev; /* for pci chipsets */ + struct pci_dev *pci_dev; /* for pci chipsets */ ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ @@ -353,14 +356,15 @@ typedef struct hwif_s { typedef void (ide_handler_t)(ide_drive_t *); typedef struct hwgroup_s { + spinlock_t spinlock; /* protects "busy" and "handler" */ ide_handler_t *handler;/* irq handler, if active */ + int busy; /* BOOL: protects all fields below */ ide_drive_t *drive; /* current drive */ ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ struct request *rq; /* current request */ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ unsigned long poll_timeout; /* timeout value during long polls */ - int active; /* set when servicing requests */ } ide_hwgroup_t; /* @@ -393,7 +397,7 @@ typedef struct ide_settings_s { struct ide_settings_s *next; } ide_settings_t; -void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); +void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); void ide_remove_setting(ide_drive_t *drive, char *name); ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); @@ -663,6 +667,7 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout); */ struct request **ide_get_queue (kdev_t dev); +int ide_spin_wait_hwgroup(const char *msg, ide_drive_t *drive, unsigned long *flags); void ide_timer_expiry (unsigned long data); void ide_intr (int irq, void *dev_id, struct pt_regs *regs); void ide_geninit (struct gendisk *gd); @@ -689,6 +694,9 @@ extern struct file_operations ide_fops[]; #endif #ifdef _IDE_C +#ifdef CONFIG_BLK_DEV_IDE +int ideprobe_init (void); +#endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_BLK_DEV_IDEDISK int idedisk_init (void); #endif /* CONFIG_BLK_DEV_IDEDISK */ @@ -722,13 +730,9 @@ int ide_build_dmatable (ide_drive_t *drive); void ide_dma_intr (ide_drive_t *drive); int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; -unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_t *hwif, int extra, const char *name) __init; +unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; #endif -#ifdef CONFIG_BLK_DEV_IDE -int ideprobe_init (void); -#endif /* CONFIG_BLK_DEV_IDE */ - #ifdef CONFIG_BLK_DEV_PDC4030 #include "pdc4030.h" #define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 900ed785a3c8..d1201086ddd0 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -448,7 +448,7 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) info.lo_flags = lo->lo_flags; strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE); info.lo_encrypt_type = lo->lo_encrypt_type; - if (lo->lo_encrypt_key_size && suser()) { + if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info.lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); diff --git a/drivers/block/md.c b/drivers/block/md.c index 674c378b1fb9..8b4b487e1e07 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -622,7 +622,7 @@ static int md_ioctl (struct inode *inode, struct file *file, int minor, err; struct hd_geometry *loc = (struct hd_geometry *) arg; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (((minor=MINOR(inode->i_rdev)) & 0x80) && diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 70e445668256..cd733884c223 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -316,7 +316,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, struct nbd_device *lo; int dev, error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!inode) return -EINVAL; diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c index f312b251c9c4..e7006ed69e40 100644 --- a/drivers/block/ns87415.c +++ b/drivers/block/ns87415.c @@ -35,7 +35,8 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) struct pci_dev *dev = hwif->pci_dev; unsigned long flags; - save_flags(flags); cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ new = *old; /* adjust IRQ enable bit */ @@ -56,7 +57,7 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) *old = new; (void) pci_write_config_dword(dev, 0x40, new); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } static void ns87415_selectproc (ide_drive_t *drive) @@ -66,33 +67,25 @@ static void ns87415_selectproc (ide_drive_t *drive) static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = HWIF(drive); + byte dma_stat; switch (func) { case ide_dma_end: /* returns 1 on error, 0 otherwise */ - { - byte dma_stat = inb(hwif->dma_base+2); - int rc = (dma_stat & 7) != 4; - /* from errata: stop DMA, clear INTR & ERROR */ - outb(7, hwif->dma_base); - /* clear the INTR & ERROR bits */ - outb(dma_stat|6, hwif->dma_base+2); - /* verify good DMA status */ - return rc; - } + drive->waiting_for_dma = 0; + dma_stat = inb(hwif->dma_base+2); + outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */ + outb(dma_stat|6, hwif->dma_base+2); /* clear the INTR & ERROR bits */ + return (dma_stat & 7) != 4; /* verify good DMA status */ case ide_dma_write: case ide_dma_read: - /* select DMA xfer */ - ns87415_prepare_drive(drive, 1); - /* use standard DMA stuff */ - if (!ide_dmaproc(func, drive)) + ns87415_prepare_drive(drive, 1); /* select DMA xfer */ + if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */ return 0; - /* DMA failed: select PIO xfer */ - ns87415_prepare_drive(drive, 0); + ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ return 1; default: - /* use standard DMA stuff */ - return ide_dmaproc(func, drive); + return ide_dmaproc(func, drive); /* use standard DMA stuff */ } } @@ -100,8 +93,7 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) { struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; - byte progif, stat; - int timeout; + byte progif; /* * We cannot probe for IRQ: both ports share common IRQ on INTA. @@ -134,6 +126,9 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) pci_write_config_byte(dev, 0x55, 0xee); #ifdef __sparc_v9__ +{ + int timeout; + byte stat; /* * XXX: Reset the device, if we don't it will not respond * to SELECT_DRIVE() properly during first probe_hwif(). @@ -148,6 +143,7 @@ __initfunc(void ide_init_ns87415 (ide_hwif_t *hwif)) if (stat == 0xff) break; } while ((stat & BUSY_STAT) && --timeout); +} #endif } if (!using_inta) diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c index a6be01938b99..41b87fbbe3b5 100644 --- a/drivers/block/opti621.c +++ b/drivers/block/opti621.c @@ -242,8 +242,8 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) hwif->name, ax, second.data_time, second.recovery_time, drdy); #endif - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ reg_base = hwif->io_ports[IDE_DATA_OFFSET]; outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ @@ -268,7 +268,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio) write_reg(misc, MISC_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } /* diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index aa431ae33dfa..c2f9473bc661 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -466,7 +466,7 @@ static int pd_ioctl(struct inode *inode,struct file *file, put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; @@ -484,12 +484,14 @@ static int pd_ioctl(struct inode *inode,struct file *file, put_user(pd_hd[dev].nr_sects,(long *) arg); return (0); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return pd_revalidate(inode->i_rdev); RO_IOCTLS(inode->i_rdev,arg); default: diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 00d629ddde9d..b894e2cc9b6a 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -416,7 +416,7 @@ static int pf_ioctl(struct inode *inode,struct file *file, put_user(0,(long *)&geo->start); return 0; case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; @@ -434,7 +434,7 @@ static int pf_ioctl(struct inode *inode,struct file *file, put_user(PF.capacity,(long *) arg); return (0); case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index 30baff570293..b5b13b9cbb08 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -327,15 +327,9 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) do { stat=GET_STAT(); if(stat & DRQ_STAT) { -/* unsigned long flags; - save_flags(flags); - cli(); disable_irq(HWIF(drive)->irq); -*/ ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL); -/* enable_irq(HWIF(drive)->irq); - restore_flags(flags); -*/ + enable_irq(HWIF(drive)->irq); return; } if(IN_BYTE(IDE_SELECT_REG) & 0x01) @@ -353,7 +347,7 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) return; } if (!drive->unmask) - cli(); + __cli(); /* local CPU only */ HWGROUP(drive)->wrq = *rq; /* scratchpad */ promise_write(drive); return; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index cf13eccafb26..bef50bd36159 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1091,7 +1091,7 @@ static int ps2esdi_ioctl(struct inode *inode, } break; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!inode->i_rdev) return -EINVAL; @@ -1109,7 +1109,7 @@ static int ps2esdi_ioctl(struct inode *inode, } break; case BLKFLSBUF: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!inode->i_rdev) return -EINVAL; @@ -1118,6 +1118,8 @@ static int ps2esdi_ioctl(struct inode *inode, return 0; case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); RO_IOCTLS(inode->i_rdev, arg); } diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c index 9c13bfea98e4..9c1d0ed71317 100644 --- a/drivers/block/qd6580.c +++ b/drivers/block/qd6580.c @@ -49,13 +49,13 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 3, NULL); - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ outb_p(0x8d,0xb0); outb_p(0x0 ,0xb2); outb_p(((pio+1)<<4)|0x0f,0xb3); inb(0x3f6); - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } void init_qd6580 (void) diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 180a090d1263..a3366d04bd72 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -164,7 +164,7 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un switch (cmd) { case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c index 83426bc5eeb5..ef05e4656f74 100644 --- a/drivers/block/sl82c105.c +++ b/drivers/block/sl82c105.c @@ -19,8 +19,9 @@ int chrp_ide_ports_known = 0; ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; ide_ioreg_t chrp_idedma_regbase; -void ide_init_sl82c105(struct pci_dev *dev) { - +void ide_init_sl82c105(ide_hwif_t *hwif) +{ + struct pci_dev *dev = hwif->pci_dev; unsigned short t16; unsigned int t32; @@ -37,15 +38,7 @@ void ide_init_sl82c105(struct pci_dev *dev) { pci_write_config_dword(dev, 0x40, 0x10ff08a1); } - -void ide_probe_for_sl82c105(void) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, dev))) - ide_init_sl82c105(dev); -} - +#if 0 /* nobody ever calls these.. ?? */ void chrp_ide_probe(void) { struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); @@ -75,4 +68,4 @@ void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) if (irq != NULL) *irq = chrp_ide_irq; } - +#endif diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 474d434a2d30..2b0678849679 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -148,8 +148,8 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) /* select PIO or DMA */ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82); - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ if (reg != hwif->select_data) { hwif->select_data = reg; @@ -164,7 +164,7 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) outw(reg, hwif->config_data+3); } - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ } static void trm290_selectproc (ide_drive_t *drive) @@ -189,15 +189,20 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) break; /* try PIO instead of DMA */ trm290_prepare_drive(drive, 1); /* select DMA xfer */ outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base); + drive->waiting_for_dma = 1; outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); + return 0; case ide_dma_begin: return 0; case ide_dma_end: + drive->waiting_for_dma = 0; return (inw(hwif->dma_base+2) != 0x00ff); + case ide_dma_test_irq: + return (inw(hwif->dma_base+2) == 0x00ff); default: return ide_dmaproc(func, drive); } @@ -226,8 +231,8 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data); } - save_flags(flags); - cli(); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ /* put config reg into first byte of hwif->select_data */ outb(0x51|(hwif->channel<<3), hwif->config_data+1); hwif->select_data = 0x21; /* select PIO as default */ @@ -235,13 +240,13 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif)) reg = inb(hwif->config_data+3); /* get IRQ info */ reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */ outb(reg, hwif->config_data+3); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ if ((reg & 0x10)) hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */ - ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 2); + ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); hwif->dmaproc = &trm290_dmaproc; hwif->selectproc = &trm290_selectproc; hwif->no_autodma = 1; /* play it safe for now */ diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c index 8856dad35c72..77121ca3e017 100644 --- a/drivers/block/umc8672.c +++ b/drivers/block/umc8672.c @@ -112,39 +112,39 @@ static void tune_umc (ide_drive_t *drive, byte pio) pio = ide_get_best_pio_mode(drive, pio, 4, NULL); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); - save_flags(flags); - cli(); + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ if (hwgroup && hwgroup->handler != NULL) { printk("umc8672: other interface is busy: exiting tune_umc()\n"); } else { current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; umc_set_speeds (current_speeds); } - restore_flags(flags); + restore_flags(flags); /* all CPUs */ } void init_umc8672 (void) /* called from ide.c */ { unsigned long flags; - save_flags(flags); - cli (); + __save_flags(flags); /* local CPU only */ + __cli(); /* local CPU only */ if (check_region(0x108, 2)) { - restore_flags(flags); + __restore_flags(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; } outb_p (0x5A,0x108); /* enable umc */ if (in_umc (0xd5) != 0xa0) { - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ printk ("umc8672: not found\n"); return; } outb_p (0xa5,0x108); /* disable umc */ umc_set_speeds (current_speeds); - restore_flags(flags); + __restore_flags(flags); /* local CPU only */ request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 7a26e28ac33c..b7d604db884a 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -338,7 +338,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -348,12 +348,12 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) if (!arg) return -EINVAL; return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); case BLKFLSBUF: /* Return devices size */ - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case HDIO_SET_DMA: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; nodma = !arg; if (nodma && xd_dma_buffer) { @@ -366,6 +366,8 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) case HDIO_GET_MULTCOUNT: return put_user(xd_maxsectors, (long *) arg); case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return xd_reread_partitions(inode->i_rdev); RO_IOCTLS(inode->i_rdev,arg); default: diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index a3b3e2989689..539794595342 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -4189,7 +4189,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, switch (cmd) /* Sun-compatible */ { case DDIOCSDBG: /* DDI Debug */ - if (!suser()) RETURN_UP(-EPERM); + if (!capable(CAP_SYS_ADMIN)) RETURN_UP(-EPERM); i=sbpcd_dbg_ioctl(arg,1); RETURN_UP(i); case CDROMRESET: /* hard reset the drive */ @@ -4478,7 +4478,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, } /* end of CDROMREADAUDIO */ case BLKRASET: - if(!suser()) RETURN_UP(-EACCES); + if(!capable(CAP_SYS_ADMIN)) RETURN_UP(-EACCES); if(!(cdi->dev)) RETURN_UP(-EINVAL); if(arg > 0xff) RETURN_UP(-EINVAL); read_ahead[MAJOR(cdi->dev)] = arg; diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c index f4fcf4f7bb92..c461cf7098f5 100644 --- a/drivers/char/apm_bios.c +++ b/drivers/char/apm_bios.c @@ -1050,7 +1050,7 @@ static int do_open(struct inode * inode, struct file * filp) * we might close the device immediately without doing a * privileged operation -- cevans */ - as->suser = suser(); + as->suser = capable(CAP_SYS_ADMIN); as->next = user_list; user_list = as; filp->private_data = as; diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index ec66585cfe1b..97d5794f14e4 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -1581,7 +1581,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCSFBUF: { struct video_buffer v; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; @@ -1680,7 +1680,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return 0; case BTTV_WRITEE: - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; if(copy_from_user((void *) eedata, (void *) arg, 256)) return -EFAULT; @@ -1688,7 +1688,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return 0; case BTTV_READEE: - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; readee(&(btv->i2c), eedata); if(copy_to_user((void *) arg, (void *) eedata, 256)) diff --git a/drivers/char/console.c b/drivers/char/console.c index dc437cc2f083..06d80edf34b0 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -331,7 +331,7 @@ int vc_allocate(unsigned int i) /* return 0 on success */ long p, q; /* prevent users from taking too much memory */ - if (i >= MAX_NR_USER_CONSOLES && !suser()) + if (i >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) return -EPERM; /* due to the granularity of kmalloc, we waste some memory here */ diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 2ea9cb86f53b..553bf273bc63 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -926,7 +926,7 @@ static int startup(struct esp_struct * info) "esp serial", info); if (retval) { - if (suser()) { + if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1499,7 +1499,7 @@ static int set_serial_info(struct esp_struct * info, if (change_irq && (info->line % 8)) return -EINVAL; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if (change_irq || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c index 3b80c207f54e..da2010ceba40 100644 --- a/drivers/char/ftape/zftape/zftape-ctl.c +++ b/drivers/char/ftape/zftape/zftape-ctl.c @@ -1342,9 +1342,9 @@ static int mtiocftcmd(struct mtftcmd *ftcmd, int arg_size) TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "Mag tape ioctl command: MTIOCFTCMD"); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { TRACE_ABORT(-EPERM, ft_t_info, - "only the superuser may send raw qic-117 commands"); + "need CAP_SYS_ADMIN capability to send raw qic-117 commands"); } if (zft_qic_mode) { TRACE_ABORT(-EACCES, ft_t_info, diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 2e0dd3736937..404f9c88c77b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -1774,7 +1774,7 @@ static int stli_setserial(stliport_t *portp, struct serial_struct *sp) #endif copy_from_user(&sio, sp, sizeof(struct serial_struct)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 2e2ffc3419a3..7df3eb655b7d 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -13,7 +13,7 @@ * lp_read (Status readback) support added by Carsten Gross, * carsten@sol.wohnheim.uni-ulm.de * Support for parport by Philip Blundell - * parport_sharing hacking by Andrea Arcangeli + * Parport sharing hacking by Andrea Arcangeli * Fixed kernel_(to/from)_user memory copy to check for errors * by Riccardo Facchetti */ @@ -75,6 +75,8 @@ #include #include +#undef LP_STATS +#undef LP_NEED_CAREFUL #include #include @@ -87,17 +89,23 @@ struct lp_struct lp_table[LP_NO] = { [0 ... LP_NO-1] = {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, - NULL, 0, 0, 0, {0}} + NULL, +#ifdef LP_STATS + 0, 0, {0}, +#endif + NULL, 0} }; /* Test if printer is ready (and optionally has no error conditions) */ +#ifdef LP_NEED_CAREFUL #define LP_READY(minor, status) \ - ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY)) -#define LP_CAREFUL_READY(minor, status) \ - ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1) + ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : ((status) & LP_PBUSY)) #define _LP_CAREFUL_READY(status) \ - (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ + ((status) & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ (LP_PBUSY|LP_PSELECD|LP_PERRORP) +#else +#define LP_READY(minor, status) ((status) & LP_PBUSY) +#endif #undef LP_DEBUG #undef LP_READ_DEBUG @@ -108,8 +116,8 @@ static int lp_preempt(void *handle) { struct lp_struct *lps = (struct lp_struct *)handle; - if (waitqueue_active (&lps->dev->wait_q)) - wake_up_interruptible(&lps->dev->wait_q); + if (waitqueue_active (&lps->wait_q)) + wake_up_interruptible(&lps->wait_q); /* Don't actually release the port now */ return 1; @@ -157,31 +165,29 @@ static int lp_reset(int minor) static inline int lp_char(char lpchar, int minor) { - int status; + unsigned char status; unsigned int wait = 0; unsigned long count = 0; +#ifdef LP_STATS struct lp_stats *stats; +#endif - for (;;) { + for (;;) + { lp_yield(minor); status = r_str (minor); - if (++count == LP_CHAR(minor)) + if (LP_READY(minor, status)) + break; + if (!LP_POLLED(minor) || ++count == LP_CHAR(minor) || + signal_pending(current)) return 0; - if (LP_POLLING(minor)) - { - if (LP_READY(minor, status)) - break; - } else { - if (!LP_READY(minor, status)) - return 0; - else - break; - } } w_dtr(minor, lpchar); +#ifdef LP_STATS stats = &LP_STAT(minor); stats->chars++; +#endif /* must wait before taking strobe high, and after taking strobe low, according spec. Some printers need it, others don't. */ #ifndef __sparc__ @@ -200,6 +206,8 @@ static inline int lp_char(char lpchar, int minor) #endif /* take strobe low */ w_ctr(minor, LP_PSELECP | LP_PINITP); + +#ifdef LP_STATS /* update waittime statistics */ if (count > stats->maxwait) { #ifdef LP_DEBUG @@ -212,6 +220,7 @@ static inline int lp_char(char lpchar, int minor) stats->meanwait - count; stats->meanwait = (255 * stats->meanwait + count + 128) / 256; stats->mdev = ((127 * stats->mdev) + wait + 64) / 128; +#endif return 1; } @@ -220,13 +229,13 @@ static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct lp_struct *lp_dev = (struct lp_struct *) dev_id; - if (waitqueue_active (&lp_dev->dev->wait_q)) - wake_up_interruptible(&lp_dev->dev->wait_q); + if (waitqueue_active (&lp_dev->wait_q)) + wake_up_interruptible(&lp_dev->wait_q); } static void lp_error(int minor) { - if (LP_POLLING(minor) || LP_PREEMPTED(minor)) { + if (LP_POLLED(minor) || LP_PREEMPTED(minor)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIMEOUT_POLLED; lp_parport_release(minor); @@ -236,7 +245,7 @@ static void lp_error(int minor) } static int lp_check_status(int minor) { - static unsigned char last = 0; + unsigned int last = lp_table[minor].last_error; unsigned char status = r_str(minor); if ((status & LP_POUTPA)) { if (last != LP_POUTPA) { @@ -256,6 +265,8 @@ static int lp_check_status(int minor) { } else last = 0; + lp_table[minor].last_error = last; + if (last != 0) { if (LP_F(minor) & LP_ABORT) return 1; @@ -265,7 +276,7 @@ static int lp_check_status(int minor) { return 0; } -static inline int lp_write_buf(unsigned int minor, const char *buf, int count) +static int lp_write_buf(unsigned int minor, const char *buf, int count) { unsigned long copy_size; unsigned long total_bytes_written = 0; @@ -275,9 +286,11 @@ static inline int lp_write_buf(unsigned int minor, const char *buf, int count) if (minor >= LP_NO) return -ENXIO; - if (lp_table[minor].dev == NULL) + if (lp->dev == NULL) return -ENXIO; + lp_table[minor].last_error = 0; + do { bytes_written = 0; copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); @@ -289,55 +302,69 @@ static inline int lp_write_buf(unsigned int minor, const char *buf, int count) if (lp_char(lp->lp_buffer[bytes_written], minor)) { --copy_size; ++bytes_written; - lp_table[minor].runchars++; +#ifdef LP_STATS + lp->runchars++; +#endif } else { int rc = total_bytes_written + bytes_written; - if (lp_table[minor].runchars > LP_STAT(minor).maxrun) - LP_STAT(minor).maxrun = lp_table[minor].runchars; + +#ifdef LP_STATS + if (lp->runchars > LP_STAT(minor).maxrun) + LP_STAT(minor).maxrun = lp->runchars; LP_STAT(minor).sleeps++; +#endif - if (LP_POLLING(minor)) { - lp_polling: + if (signal_pending(current)) { + if (total_bytes_written + bytes_written) + return total_bytes_written + bytes_written; + else + return -EINTR; + } + +#ifdef LP_STATS + lp->runchars = 0; +#endif + + if (LP_POLLED(minor)) { if (lp_check_status(minor)) return rc ? rc : -EIO; -#ifdef LP_DEBUG - printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp_table[minor].runchars, LP_TIME(minor)); + lp_polling: +#if defined(LP_DEBUG) && defined(LP_STATS) + printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor)); #endif current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIME(minor); lp_schedule (minor); } else { cli(); - if (LP_PREEMPTED(minor)) { + if (LP_PREEMPTED(minor)) + { + /* + * We can' t sleep on the interrupt + * since another pardevice need the port. + */ sti(); goto lp_polling; } - enable_irq(lp->dev->port->irq); - w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN); + w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); status = r_str(minor); - if ((!(status & LP_PACK) || (status & LP_PBUSY)) - && LP_CAREFUL_READY(minor, status)) { + if (!(status & LP_PACK) || (status & LP_PBUSY)) + { + /* + * The interrupt is happened in the + * meantime so don' t wait for it. + */ w_ctr(minor, LP_PSELECP | LP_PINITP); sti(); continue; } current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; - interruptible_sleep_on(&lp->dev->wait_q); - disable_irq(lp->dev->port->irq); + interruptible_sleep_on(&lp->wait_q); w_ctr(minor, LP_PSELECP | LP_PINITP); sti(); if (lp_check_status(minor)) return rc ? rc : -EIO; } - - lp_table[minor].runchars = 0; - - if (signal_pending(current)) { - if (total_bytes_written + bytes_written) - return total_bytes_written + bytes_written; - else - return -EINTR; - } } } @@ -356,10 +383,12 @@ static ssize_t lp_write(struct file * file, const char * buf, unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); ssize_t retv; +#ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) lp_table[minor].runchars = 0; lp_table[minor].lastcall = jiffies; +#endif /* Claim Parport or sleep until it becomes available */ @@ -495,9 +524,8 @@ static int lp_open(struct inode * inode, struct file * file) return -ENXIO; if ((LP_F(minor) & LP_EXIST) == 0) return -ENXIO; - if (LP_F(minor) & LP_BUSY) + if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor)) & LP_BUSY) return -EBUSY; - LP_F(minor) |= LP_BUSY; MOD_INC_USE_COUNT; @@ -543,8 +571,8 @@ static int lp_release(struct inode * inode, struct file * file) kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; - LP_F(minor) &= ~LP_BUSY; MOD_DEC_USE_COUNT; + LP_F(minor) &= ~LP_BUSY; return 0; } @@ -581,12 +609,14 @@ static int lp_ioctl(struct inode *inode, struct file *file, else LP_F(minor) &= ~LP_ABORTOPEN; break; +#ifdef LP_NEED_CAREFUL case LPCAREFUL: if (arg) LP_F(minor) |= LP_CAREFUL; else LP_F(minor) &= ~LP_CAREFUL; break; +#endif case LPWAIT: LP_WAIT(minor) = arg; break; @@ -609,6 +639,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, case LPRESET: lp_reset(minor); break; +#ifdef LP_STATS case LPGETSTATS: if (copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats))) @@ -617,6 +648,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); break; +#endif case LPGETFLAGS: status = LP_F(minor); if (copy_to_user((int *) arg, &status, sizeof(int))) diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 329ac7b326a2..fba8c7d5125f 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -285,7 +285,7 @@ static int nvram_ioctl( struct inode *inode, struct file *file, switch( cmd ) { case NVRAM_INIT: /* initialize NVRAM contents and checksum */ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return( -EACCES ); save_flags(flags); @@ -301,7 +301,7 @@ static int nvram_ioctl( struct inode *inode, struct file *file, case NVRAM_SETCKS: /* just set checksum, contents unchanged * (maybe useful after checksum garbaged * somehow...) */ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return( -EACCES ); save_flags(flags); diff --git a/drivers/char/random.c b/drivers/char/random.c index 226694a7145e..13d5d6d36de1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1199,7 +1199,7 @@ random_ioctl(struct inode * inode, struct file * file, put_user(ent_count, (int *) arg); return 0; case RNDADDTOENTCNT: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); if (retval) @@ -1228,7 +1228,7 @@ random_ioctl(struct inode * inode, struct file * file, wake_up_interruptible(&random_read_wait); return 0; case RNDGETPOOL: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int)); @@ -1249,7 +1249,7 @@ random_ioctl(struct inode * inode, struct file * file, return -EFAULT; return 0; case RNDADDENTROPY: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int)); @@ -1287,13 +1287,13 @@ random_ioctl(struct inode * inode, struct file * file, wake_up_interruptible(&random_read_wait); return 0; case RNDZAPENTCNT: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; random_state.entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; rand_clear_pool(); return 0; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index bed251b19ec9..b854fa338049 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1447,7 +1447,7 @@ extern inline int rc_set_serial_info(struct riscom_port * port, change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 901077455a45..cb4e9d4982ea 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1315,7 +1315,7 @@ static int set_config(struct r_port * info, struct rocket_config * new_info) if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 9edca16836b0..5f827bed9719 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -220,7 +220,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > 64) && (!suser())) + if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { @@ -308,7 +308,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int yrs; unsigned long flags; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EACCES; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, @@ -394,7 +394,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > 64) && (!suser())) + if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<tty) set_bit(TTY_IO_ERROR, &info->tty->flags); } else @@ -1005,7 +1005,7 @@ static int startup(struct async_struct * info) retval = request_irq(state->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { - if (suser()) { + if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1638,7 +1638,7 @@ static int set_serial_info(struct async_struct * info, change_port = (new_serial.port != state->port) || (new_serial.hub6 != state->hub6); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if (change_irq || change_port || (new_serial.baud_base != state->baud_base) || (new_serial.type != state->type) || @@ -1837,7 +1837,7 @@ static int do_autoconfig(struct async_struct * info) { int retval; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (info->state->count > 1) @@ -1922,7 +1922,7 @@ static int set_multiport_struct(struct async_struct * info, int retval; void (*handler)(int, void *, struct pt_regs *); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; state = info->state; diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index ef5e6f7c7b06..a5d66bbd8f6d 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -1842,7 +1842,7 @@ extern inline int sx_set_serial_info(struct specialix_port * port, change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 31fa5ab50029..06795e07ab40 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -1338,7 +1338,7 @@ static int stl_setserial(stlport_t *portp, struct serial_struct *sp) #endif copy_from_user(&sio, sp, sizeof(struct serial_struct)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 226f4a80b935..fd3002d05676 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -249,7 +249,8 @@ do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kb if (!(key_map = key_maps[s])) { int j; - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser()) + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) return -EPERM; key_map = (ushort *) kmalloc(sizeof(plain_map), @@ -268,7 +269,7 @@ do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kb /* * Attention Key. */ - if (((ov == K_SAK) || (v == K_SAK)) && !suser()) + if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) return -EPERM; key_map[i] = U(v); if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 67c39c675de3..d94a8a771870 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -384,7 +384,7 @@ static int capi_ioctl(struct inode *inode, struct file *file, struct capi_manufacturer_cmd mcmd; if (minor) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, sizeof(mcmd)); diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 4232f5953ebd..9c3f18c9e17b 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -964,7 +964,7 @@ static int set_serial_info(struct mac_serial * info, copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || (new_serial.close_delay != info->close_delay) || diff --git a/drivers/misc/TODO-parport b/drivers/misc/TODO-parport index 08860cc27956..523a1ca9436c 100644 --- a/drivers/misc/TODO-parport +++ b/drivers/misc/TODO-parport @@ -6,20 +6,13 @@ Things to be done. 2. A better lp.c: - a) It's a _mess_ - - b) ECP support would be nice. This can only work if both the port and + a) ECP support would be nice. This can only work if both the port and the printer support it. - c) Errors could do with being handled better. There's no point logging a - message every 10 seconds when the printer is out of paper. - - d) Handle status readback automatically. IEEE1284 printers can post status + b) Handle status readback automatically. IEEE1284 printers can post status bits when they have something to say. We should read out and deal with (maybe just log) whatever the printer wants to tell the world. 3. Support more hardware (eg m68k, Sun bpp). 4. A better PLIP (make use of bidirectional/ECP/EPP ports). - - diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index bb9ee3c30c78..ae344c99dcdb 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1,8 +1,8 @@ /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ /* - Written 1993-1995 by Donald Becker. + Written 1993-1997 by Donald Becker. - Copyright 1994,1995 by Donald Becker. + Copyright 1994-1997 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and distributed according to the terms of the GNU Public License, @@ -27,10 +27,22 @@ FIXES: Alan Cox: Removed the 'Unexpected interrupt' bug. Michael Meskes: Upgraded to Donald Becker's version 1.07. - Phil Blundell: Media selection support. + Alan Cox: Increased the eeprom delay. Regardless of + what the docs say some people definitely + get problems with lower (but in card spec) + delays + v1.10 4/21/97 Fixed module code so that multiple cards may be detected, + other cleanups. -djb + Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. */ -static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n"; +/* A few values that may be tweaked. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (400*HZ/1000) +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +#define INTR_WORK 10 #include @@ -48,20 +60,19 @@ static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n"; #include #include #include /* for udelay() */ -#include #include #include #ifdef EL3_DEBUG -static int el3_debug = EL3_DEBUG; +int el3_debug = EL3_DEBUG; #else -static int el3_debug = 2; +int el3_debug = 2; #endif /* To minimize the size of the driver source I only define operating constants if they are used several times. You'll need the manual - if you want to understand driver details. */ + anyway if you want to understand driver details. */ /* Offsets from base I/O address. */ #define EL3_DATA 0x00 #define EL3_CMD 0x0e @@ -111,12 +122,14 @@ enum RxFilter { #define SKB_QUEUE_SIZE 64 struct el3_private { - struct net_device_stats stats; + struct enet_statistics stats; + struct device *next_dev; /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; }; static int id_port = 0x100; +static struct device *el3_root_dev = NULL; static ushort id_read_eeprom(int index); static ushort read_eeprom(short ioaddr, int index); @@ -124,28 +137,19 @@ static int el3_open(struct device *dev); static int el3_start_xmit(struct sk_buff *skb, struct device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void update_stats(int addr, struct device *dev); -static struct net_device_stats *el3_get_stats(struct device *dev); +static struct enet_statistics *el3_get_stats(struct device *dev); static int el3_rx(struct device *dev); static int el3_close(struct device *dev); -static int el3_set_config(struct device *dev, struct ifmap *map); -#ifdef HAVE_MULTICAST static void set_multicast_list(struct device *dev); -#endif -__initfunc(int el3_probe(struct device *dev)) +int el3_probe(struct device *dev) { short lrs_state = 0xff, i; - ushort ioaddr, irq, port; - short *phys_addr = (short *)dev->dev_addr; + ushort ioaddr, irq, if_port; + short phys_addr[3]; static int current_tag = 0; - static int el3_portmap[] = { - IF_PORT_10BASET, - IF_PORT_AUI, - IF_PORT_UNKNOWN, - IF_PORT_10BASE2 - }; /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ @@ -163,7 +167,7 @@ __initfunc(int el3_probe(struct device *dev)) outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); irq = inw(ioaddr + WN0_IRQ) >> 12; - port = inw(ioaddr + 6)>>14; + if_port = inw(ioaddr + 6)>>14; for (i = 0; i < 3; i++) phys_addr[i] = htons(read_eeprom(ioaddr, i)); @@ -175,18 +179,14 @@ __initfunc(int el3_probe(struct device *dev)) } } -/* - * This has to be coded according to Documentation/mca.txt before - * this driver can be used with the 3c529 MCA cards. - */ -#if 0 /* #ifdef CONFIG_MCA */ +#ifdef CONFIG_MCA if (MCA_bus) { mca_adaptor_select_mode(1); for (i = 0; i < 8; i++) if ((mca_adaptor_id(i) | 1) == 0x627c) { ioaddr = mca_pos_base_addr(i); irq = inw(ioaddr + WN0_IRQ) >> 12; - port = inw(ioaddr + 6)>>14; + if_port = inw(ioaddr + 6)>>14; for (i = 0; i < 3; i++) phys_addr[i] = htons(read_eeprom(ioaddr, i)); @@ -203,6 +203,8 @@ __initfunc(int el3_probe(struct device *dev)) outb(0x02, 0xA79); /* Return to WaitForKey state. */ /* Select an open I/O location at 0x1*0 to do contention select. */ for (id_port = 0x100; id_port < 0x200; id_port += 0x10) { + if (check_region(id_port, 1)) + continue; outb(0x00, id_port); outb(0xff, id_port); if (inb(id_port) & 0x01) @@ -218,13 +220,6 @@ __initfunc(int el3_probe(struct device *dev)) on cards as they are found. Cards with their tag set will not respond to subsequent ID sequences. */ - if (check_region(id_port,1)) { - static int once = 1; - if (once) printk("3c509: Somebody has reserved 0x%x, can't do ID_PORT lookup, nor card auto-probing\n",id_port); - once = 0; - return -ENODEV; - } - outb(0x00, id_port); outb(0x00, id_port); for(i = 0; i < 255; i++) { @@ -252,16 +247,16 @@ __initfunc(int el3_probe(struct device *dev)) { unsigned short iobase = id_read_eeprom(8); - port = iobase >> 14; + if_port = iobase >> 14; ioaddr = 0x200 + ((iobase & 0x1f) << 4); } - if (dev->irq > 1 && dev->irq < 16) + if (dev && dev->irq > 1 && dev->irq < 16) irq = dev->irq; else irq = id_read_eeprom(9) >> 12; - if (dev->base_addr != 0 - && dev->base_addr != (unsigned short)ioaddr) { + if (dev && dev->base_addr != 0 + && dev->base_addr != (unsigned short)ioaddr) { return -ENODEV; } @@ -278,15 +273,20 @@ __initfunc(int el3_probe(struct device *dev)) /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); found: + if (dev == NULL) { + dev = init_etherdev(dev, sizeof(struct el3_private)); + } + memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - dev->if_port = el3_portmap[port]; + dev->if_port = (dev->mem_start & 0x1f) ? dev->mem_start & 3 : if_port; + request_region(dev->base_addr, EL3_IO_EXTENT, "3c509"); { - static const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; + const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ", - dev->name, dev->base_addr, current_tag, if_names[port]); + dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); } /* Read in the station address. */ @@ -295,11 +295,15 @@ __initfunc(int el3_probe(struct device *dev)) printk(", IRQ %d.\n", dev->irq); /* Make up a EL3-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct el3_private)); + ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; + el3_root_dev = dev; + if (el3_debug > 0) printk(version); @@ -308,30 +312,26 @@ __initfunc(int el3_probe(struct device *dev)) dev->hard_start_xmit = &el3_start_xmit; dev->stop = &el3_close; dev->get_stats = &el3_get_stats; - dev->set_config = &el3_set_config; -#ifdef HAVE_MULTICAST - dev->set_multicast_list = &set_multicast_list; -#endif + dev->set_multicast_list = &set_multicast_list; /* Fill in the generic fields of the device structure. */ ether_setup(dev); - dev->flags |= IFF_PORTSEL; return 0; } /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -__initfunc(static ushort read_eeprom(short ioaddr, int index)) +static ushort read_eeprom(short ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ - udelay (300); + udelay (500); return inw(ioaddr + 12); } /* Read a word from the EEPROM when in the ISA ID probe state. */ -__initfunc(static ushort id_read_eeprom(int index)) +static ushort id_read_eeprom(int index) { int bit, word = 0; @@ -340,8 +340,8 @@ __initfunc(static ushort id_read_eeprom(int index)) outb(EEPROM_READ + index, id_port); /* Pause for at least 162 us. for the read to take place. */ - udelay (300); - + udelay (500); + for (bit = 15; bit >= 0; bit--) word = (word << 1) + (inb(id_port) & 0x01); @@ -352,59 +352,6 @@ __initfunc(static ushort id_read_eeprom(int index)) } - -static int -el3_set_config(struct device *dev, struct ifmap *map) -{ - int ioaddr = dev->base_addr; - if (map->port != dev->if_port) { - switch (map->port) { - case IF_PORT_10BASE2: - case IF_PORT_10BASET: - case IF_PORT_AUI: - if (dev->start) { - if (dev->if_port == IF_PORT_10BASE2) - /* Turn off thinnet power. */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == IF_PORT_10BASET) { - /* Disable link beat and jabber */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); - EL3WINDOW(1); - } - } - printk(KERN_INFO "%s: %s port selected.\n", dev->name, - if_port_text[map->port]); - dev->if_port = map->port; - if (dev->start) { - if (dev->if_port == IF_PORT_10BASE2) - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - else if (dev->if_port == IF_PORT_10BASET) { - /* 10baseT interface, enabled link beat and jabber check. */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); - EL3WINDOW(1); - } - } - break; - default: - printk(KERN_ERR "%s: %s port not supported.\n", dev->name, - if_port_text[map->port]); - return -EINVAL; - } - } - if (map->irq != dev->irq) { - printk(KERN_ERR "%s: cannot change interrupt.\n", dev->name); - return -EINVAL; - } - if (map->base_addr != dev->base_addr) { - printk(KERN_ERR "%s: cannot change base address.\n", dev->name); - return -EINVAL; - } - return 0; -} - static int el3_open(struct device *dev) @@ -437,10 +384,10 @@ el3_open(struct device *dev) for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); - if (dev->if_port == IF_PORT_10BASE2) + if (dev->if_port == 3) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); - else if (dev->if_port == IF_PORT_10BASET) { + else if (dev->if_port == 0) { /* 10baseT interface, enabled link beat and jabber check. */ EL3WINDOW(4); outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); @@ -483,7 +430,8 @@ el3_open(struct device *dev) return 0; /* Always succeed */ } -static int el3_start_xmit(struct sk_buff *skb, struct device *dev) +static int +el3_start_xmit(struct sk_buff *skb, struct device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; int ioaddr = dev->base_addr; @@ -491,7 +439,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev) /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 40*HZ/100) + if (tickssofar < TX_TIMEOUT) return 1; printk("%s: transmit timed out, Tx_status %2.2x status %4.4x " "Tx FIFO room %d.\n", @@ -532,12 +480,15 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev) if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - lp->stats.tx_bytes+=skb->len; /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); outw(0x00, ioaddr + TX_FIFO); /* ... and the packet rounded to a doubleword. */ +#ifdef __powerpc__ + outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); +#else outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); +#endif dev->trans_start = jiffies; if (inw(ioaddr + TX_FREE) > 1536) { @@ -570,7 +521,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *)dev_id; int ioaddr, status; - int i = 0; + int i = INTR_WORK; if (dev == NULL) { printk ("el3_interrupt(): irq %d for unknown device.\n", irq); @@ -622,7 +573,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } - if (++i > 10) { + if (--i < 0) { printk("%s: Infinite loop in interrupt, status %4.4x.\n", dev->name, status); /* Clear all interrupts. */ @@ -643,7 +594,8 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } -static struct net_device_stats *el3_get_stats(struct device *dev) +static struct enet_statistics * +el3_get_stats(struct device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; unsigned long flags; @@ -720,18 +672,21 @@ el3_rx(struct device *dev) pkt_len, rx_status); if (skb != NULL) { skb->dev = dev; - skb_reserve(skb,2); /* Align IP on 16 byte */ + skb_reserve(skb, 2); /* Align IP on 16 byte */ /* 'skb->data' points to the start of sk_buff data area. */ - insl(ioaddr+RX_FIFO, skb_put(skb,pkt_len), - (pkt_len + 3) >> 2); +#ifdef __powerpc__ + insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len), + (pkt_len + 3) >> 2); +#else + insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len), + (pkt_len + 3) >> 2); +#endif - skb->protocol=eth_type_trans(skb,dev); + skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ - lp->stats.rx_bytes+=skb->len; lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; continue; } else if (el3_debug) printk("%s: Couldn't allocate a sk_buff of size %d.\n", @@ -747,7 +702,6 @@ el3_rx(struct device *dev) return 0; } -#ifdef HAVE_MULTICAST /* * Set or clear the multicast filter for this adaptor. */ @@ -772,7 +726,6 @@ set_multicast_list(struct device *dev) else outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); } -#endif static int el3_close(struct device *dev) @@ -792,10 +745,10 @@ el3_close(struct device *dev) outw(RxDisable, ioaddr + EL3_CMD); outw(TxDisable, ioaddr + EL3_CMD); - if (dev->if_port == IF_PORT_10BASE2) + if (dev->if_port == 3) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == IF_PORT_10BASET) { + else if (dev->if_port == 0) { /* Disable link beat and jabber, if_port may change ere next open(). */ EL3WINDOW(4); outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); @@ -813,69 +766,50 @@ el3_close(struct device *dev) } #ifdef MODULE -#define MAX_3C_CARDS 4 /* Max number of NE cards per module */ -#define NAMELEN 8 /* # of chars for storing dev->name */ -static char namelist[NAMELEN * MAX_3C_CARDS] = { 0, }; -static struct device dev_3c509[MAX_3C_CARDS] = { - { - NULL, /* assign a chunk of namelist[] below */ - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, NULL - }, -}; - -static int io[MAX_3C_CARDS] = { 0, }; -static int irq[MAX_3C_CARDS] = { 0, }; -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C_CARDS) "i"); +/* Parameter that may be passed into the module. */ +static int debug = -1; +static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1}; int init_module(void) { - int this_dev, found = 0; - - for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) { - struct device *dev = &dev_3c509[this_dev]; - dev->name = namelist+(NAMELEN*this_dev); - dev->irq = irq[this_dev]; - dev->base_addr = io[this_dev]; - dev->init = el3_probe; - if (io[this_dev] == 0) { - if (this_dev != 0) break; /* only complain once */ - printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n"); - } - if (register_netdev(dev) != 0) { - printk(KERN_WARNING "3c509.c: No 3c509 card found (i/o = 0x%x).\n", io[this_dev]); - if (found != 0) return 0; /* Got at least one. */ - return -ENXIO; - } - found++; + int el3_cards = 0; + + if (debug >= 0) + el3_debug = debug; + + el3_root_dev = NULL; + while (el3_probe(0) == 0) { + if (irq[el3_cards] > 1) + el3_root_dev->irq = irq[el3_cards]; + if (xcvr[el3_cards] >= 0) + el3_root_dev->if_port = xcvr[el3_cards]; + el3_cards++; } - return 0; + + return el3_cards ? 0 : -ENODEV; } void cleanup_module(void) { - int this_dev; - - for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) { - struct device *dev = &dev_3c509[this_dev]; - if (dev->priv != NULL) { - unregister_netdev(dev); - kfree_s(dev->priv,sizeof(struct el3_private)); - dev->priv = NULL; - free_irq(dev->irq, dev); - release_region(dev->base_addr, EL3_IO_EXTENT); - } + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (el3_root_dev) { + next_dev = ((struct el3_private *)el3_root_dev->priv)->next_dev; + unregister_netdev(el3_root_dev); + release_region(el3_root_dev->base_addr, EL3_IO_EXTENT); + kfree(el3_root_dev); + el3_root_dev = next_dev; } } #endif /* MODULE */ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c509.c" + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a9ddfa475220..6bb3dfd54e83 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1957,7 +1957,7 @@ static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index c0c52d24fb14..06f527d7072b 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -5487,7 +5487,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) if (status) break; status = -EPERM; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) break; status = 0; copy_from_user(tmp.addr, ioc->data, ETH_ALEN); @@ -5505,7 +5505,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr |= OMR_PR; outl(omr, DE4X5_OMR); @@ -5516,7 +5516,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr &= ~OMR_PR; outb(omr, DE4X5_OMR); @@ -5531,7 +5531,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr |= OMR_PM; outl(omr, DE4X5_OMR); @@ -5552,7 +5552,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); @@ -5569,7 +5569,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_SET_OMR: /* Set the OMR Register contents */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) { copy_from_user(tmp.addr, ioc->data, 1); outl(tmp.addr[0], DE4X5_OMR); diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 56578f58ead0..0320cc322365 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1714,7 +1714,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; case DEPCA_SET_HWADDR: /* Set the hardware address */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { copy_from_user(tmp.addr, ioc->data, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++) { @@ -1736,7 +1736,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DEPCA_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { while (dev->tbusy); /* Stop ring access */ set_bit(0, (void *) &dev->tbusy); while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ @@ -1754,7 +1754,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { while (dev->tbusy); /* Stop ring access */ set_bit(0, (void *) &dev->tbusy); while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ @@ -1782,7 +1782,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; case DEPCA_SET_MCA: /* Set a multicast address */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); set_multicast_list(dev); @@ -1793,7 +1793,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DEPCA_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1801,7 +1801,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DEPCA_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1818,7 +1818,7 @@ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DEPCA_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c index 8ceb7a8c7ad7..6343463d0de2 100644 --- a/drivers/net/dlci.c +++ b/drivers/net/dlci.c @@ -322,7 +322,7 @@ int dlci_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { struct dlci_local *dlp; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return(-EPERM); dlp = dev->priv; @@ -542,7 +542,7 @@ int dlci_ioctl(unsigned int cmd, void *arg) struct dlci_add add; int err; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return(-EPERM); if(copy_from_user(&add, arg, sizeof(struct dlci_add))) diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index c896844b2e82..cc23deba7e55 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1528,7 +1528,7 @@ static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(ioaddr, data[0], data[1]); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0], data[1], data[2]); return 0; diff --git a/drivers/net/eql.c b/drivers/net/eql.c index f654b2cdd096..abb7e6c785ad 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -329,7 +329,8 @@ static int eql_close(struct device *dev) static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { - if(cmd!=EQL_GETMASTRCFG && cmd!=EQL_GETSLAVECFG && !suser()) + if(cmd!=EQL_GETMASTRCFG && cmd!=EQL_GETSLAVECFG && + !capable(CAP_NET_ADMIN)) return -EPERM; switch (cmd) { diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index f17343b409ca..315cc27daac7 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1684,7 +1684,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; case EWRK3_SET_HWADDR: /* Set the hardware address */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { csr = inb(EWRK3_CSR); csr |= (CSR_TXD | CSR_RXD); @@ -1705,7 +1705,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { csr = inb(EWRK3_CSR); csr |= CSR_PME; csr &= ~CSR_MCE; @@ -1716,7 +1716,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { csr = inb(EWRK3_CSR); csr &= ~CSR_PME; outb(csr, EWRK3_CSR); @@ -1749,7 +1749,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_SET_MCA: /* Set a multicast address */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); set_multicast_list(dev); @@ -1760,7 +1760,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1768,7 +1768,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_MCA_EN: /* Enable multicast addressing */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { csr = inb(EWRK3_CSR); csr |= CSR_MCE; csr &= ~CSR_PME; @@ -1788,7 +1788,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); @@ -1805,7 +1805,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; case EWRK3_SET_CSR: /* Set the CSR Register contents */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) { copy_from_user(tmp.addr, ioc->data, 1); outb(tmp.addr[0], EWRK3_CSR); @@ -1816,7 +1816,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_GET_EEPROM: /* Get the EEPROM contents */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { for (i = 0; i < (EEPROM_MAX >> 1); i++) { tmp.val[i] = (short) Read_EEPROM(iobase, i); } @@ -1835,7 +1835,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ - if (suser()) { + if (capable(CAP_NET_ADMIN)) { if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { copy_from_user(tmp.addr, ioc->data, EEPROM_MAX); for (i = 0; i < (EEPROM_MAX >> 1); i++) { diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c index 16e52bd98ff5..df22a0ee7fcf 100644 --- a/drivers/net/ipddp.c +++ b/drivers/net/ipddp.c @@ -307,7 +307,7 @@ static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data; - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EPERM; switch(cmd) diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 9dd39b7b3543..9d4a237c7348 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -2281,7 +2281,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, /* * The user must have an euid of root to do these requests. */ - if (!suser ()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* * Set the MRU value diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 7424a20d402d..3e15ce47db4f 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -57,7 +57,7 @@ proc_bus_pci_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) * undefined locations (think of Intel PIIX4 as a typical example). */ - if (fsuser()) + if (capable(CAP_SYS_ADMIN)) size = PCI_CFG_SPACE_SIZE; else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) size = 128; diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index ccc8dd2cd581..160c7e5de7cf 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -91,7 +91,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTCSET: - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EPERM; copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT); diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index cb822dd2a30d..81a8b7477e57 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -205,7 +205,7 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) unsigned char *buffer; int ret; - if(!suser()) return -EPERM; + if(!capable(CAP_SYS_ADMIN)) return -EPERM; switch(cmd) { case VFC_I2C_SEND: diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index f7c477ea4b70..3d8d24a02cba 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1265,7 +1265,7 @@ static int set_serial_info(struct sun_serial * info, return -EFAULT; old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || (new_serial.close_delay != info->close_delay) || diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index cc05c37864e4..05c0ecab9f2b 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -327,7 +327,7 @@ static void idescsi_pc_intr (ide_drive_t *drive) if ((status & DRQ_STAT) == 0) { /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); - ide_sti(); + ide__sti(); if (status & ERR_STAT) rq->errors++; idescsi_end_request (1, HWGROUP(drive)); diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index ebdcb560c637..5e67230e36bf 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -50,13 +50,6 @@ NULL, /* cur_cmd */ \ #include "ppa.h" #include -#ifdef CONFIG_KMOD -#include -#ifndef PARPORT_MODULES -#define PARPORT_MODULES "parport_pc" -#endif -#endif - #define NO_HOSTS 4 static ppa_struct ppa_hosts[NO_HOSTS] = {PPA_EMPTY, PPA_EMPTY, PPA_EMPTY, PPA_EMPTY}; @@ -98,7 +91,6 @@ static int ppa_pb_claim(int host_no) return 1; } - PPA_BASE(host_no) = ppa_hosts[host_no].dev->port->base; if (ppa_hosts[host_no].cur_cmd) ppa_hosts[host_no].cur_cmd->SCp.phase++; return 0; @@ -130,12 +122,8 @@ int ppa_detect(Scsi_Host_Template * host) nhosts = 0; try_again = 0; -#ifdef CONFIG_KMOD - if (!pb) { - request_module(PARPORT_MODULES); + if (!pb) pb = parport_enumerate(); - } -#endif if (!pb) { printk("ppa: parport reports no devices.\n"); @@ -155,7 +143,7 @@ int ppa_detect(Scsi_Host_Template * host) if (ppa_pb_claim(i)) while (ppa_hosts[i].p_busy) schedule(); /* Whe can safe schedule() here */ - ppb = PPA_BASE(i); + ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base; w_ctr(ppb, 0x0c); modes = ppa_hosts[i].dev->port->modes; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index e2f933fb3c5d..b5692acd1a0f 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -379,13 +379,13 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) put_user( dev->host->host_no, (int *) arg); return 0; case SCSI_IOCTL_TAGGED_ENABLE: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!dev->tagged_supported) return -EINVAL; dev->tagged_queue = 1; dev->current_tag = 1; return 0; case SCSI_IOCTL_TAGGED_DISABLE: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!dev->tagged_supported) return -EINVAL; dev->tagged_queue = 0; dev->current_tag = 0; @@ -393,7 +393,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) case SCSI_IOCTL_PROBE_HOST: return ioctl_probe(dev->host, arg); case SCSI_IOCTL_SEND_COMMAND: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; return scsi_ioctl_send_command((Scsi_Device *) dev, (Scsi_Ioctl_Command *) arg); case SCSI_IOCTL_DOORLOCK: diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c index 2f771552a17c..a29d958d1d17 100644 --- a/drivers/scsi/sd_ioctl.c +++ b/drivers/scsi/sd_ioctl.c @@ -79,7 +79,7 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne return 0; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; @@ -96,13 +96,15 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne return 0; case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; return revalidate_scsidisk(dev, 1); RO_IOCTLS(dev, arg); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 59e135bb3522..1d34cf7ec383 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -792,7 +792,7 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, return 0; case BLKRASET: - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(cdi->dev)) return -EINVAL; @@ -804,7 +804,7 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, RO_IOCTLS(cdi->dev,arg); case BLKFLSBUF: - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EACCES; if(!(cdi->dev)) return -EINVAL; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 35af3e391718..a0adf83b33bf 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2831,7 +2831,7 @@ st_ioctl(struct inode * inode,struct file * file, if (i) return (-EFAULT); - if (mtc.mt_op == MTSETDRVBUFFER && !suser()) { + if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); return (-EPERM); } diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c index 79feefb294dd..8328b14e1c4b 100644 --- a/drivers/sgi/char/sgiserial.c +++ b/drivers/sgi/char/sgiserial.c @@ -1201,7 +1201,7 @@ static int set_serial_info(struct sgi_serial * info, copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || (new_serial.close_delay != info->close_delay) || diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 96d8c6f5a946..d6480b4ee0d1 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -245,7 +245,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry) if (S_ISDIR(inode->i_mode)) goto unlink_done; if (current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto unlink_done; if ((retval = affs_remove_header(bh,inode)) < 0) @@ -363,7 +363,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry) retval = -EPERM; if (current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto rmdir_done; if (inode->i_dev != dir->i_dev) goto rmdir_done; diff --git a/fs/attr.c b/fs/attr.c index e916a2a3d115..789713164274 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -27,28 +27,28 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && (current->fsuid != inode->i_uid || - attr->ia_uid != inode->i_uid) && !fsuser()) + attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) goto error; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && - !fsuser()) + !capable(CAP_CHOWN)) goto error; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { - if ((current->fsuid != inode->i_uid) && !fsuser()) + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) goto error; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : - inode->i_gid) && !fsuser()) + inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time. */ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { - if (current->fsuid != inode->i_uid && !fsuser()) + if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) goto error; } fine: @@ -75,7 +75,7 @@ void inode_setattr(struct inode * inode, struct iattr * attr) inode->i_ctime = attr->ia_ctime; if (ia_valid & ATTR_MODE) { inode->i_mode = attr->ia_mode; - if (!in_group_p(inode->i_gid) && !fsuser()) + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) inode->i_mode &= ~S_ISGID; } mark_inode_dirty(inode); diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 60f9efe0109c..2eec54de4ac7 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -478,7 +478,7 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT ) return -ENOTTY; - if ( !autofs_oz_mode(sbi) && !fsuser() ) + if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) return -EPERM; switch(cmd) { diff --git a/fs/buffer.c b/fs/buffer.c index 5e55f89c74c0..887b9255c089 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1871,7 +1871,7 @@ asmlinkage int sys_bdflush(int func, long data) int i, error = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; if (func == 1) { diff --git a/fs/dquot.c b/fs/dquot.c index b868ac3d7b74..58393b016945 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -375,7 +375,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes) if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); if (dquot->dq_ihardlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) { + (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && + !capable(CAP_SYS_RESOURCE)) { if ((dquot->dq_flags & DQ_INODES) == 0 && need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n", @@ -387,7 +388,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes) } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) { + dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -397,7 +399,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes) } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime == 0 && !fsuser()) { + dquot->dq_itime == 0 && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -413,7 +416,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks) if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); if (dquot->dq_bhardlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) { + (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && + !capable(CAP_SYS_RESOURCE)) { if ((dquot->dq_flags & DQ_BLKS) == 0 && need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n", @@ -425,7 +429,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks) } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) { + dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -435,7 +440,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks) } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime == 0 && !fsuser()) { + dquot->dq_btime == 0 && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -1039,11 +1045,12 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) break; case Q_GETQUOTA: if (((type == USRQUOTA && current->uid != id) || - (type == GRPQUOTA && in_group_p(id))) && !fsuser()) + (type == GRPQUOTA && in_group_p(id))) && + !capable(CAP_SYS_ADMIN)) goto out; break; default: - if (!fsuser()) + if (!capable(CAP_SYS_ADMIN)) goto out; } diff --git a/fs/exec.c b/fs/exec.c index 6a054ecdde26..7defb07e3f1c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -419,6 +419,7 @@ static int exec_mmap(void) retval = new_page_tables(current); if (retval) goto fail_restore; + activate_context(current); up(&mm->mmap_sem); mmput(old_mm); return 0; @@ -564,7 +565,7 @@ flush_failed: int prepare_binprm(struct linux_binprm *bprm) { int mode; - int retval,id_change; + int retval,id_change,cap_raised; struct inode * inode = bprm->dentry->d_inode; mode = inode->i_mode; @@ -584,7 +585,7 @@ int prepare_binprm(struct linux_binprm *bprm) bprm->e_uid = current->euid; bprm->e_gid = current->egid; - id_change = 0; + id_change = cap_raised = 0; /* Set-uid? */ if (mode & S_ISUID) { @@ -630,21 +631,25 @@ int prepare_binprm(struct linux_binprm *bprm) cap_set_full(bprm->cap_effective); } - /* We use a conservative definition of suid for capabilities. - * The process is suid if the permitted set is not a subset of - * the current permitted set after the exec call. - * new permitted set = forced | (allowed & inherited) - * pP' = fP | (fI & pI) - */ - - if ((bprm->cap_permitted.cap | - (current->cap_inheritable.cap & - bprm->cap_inheritable.cap)) & - ~current->cap_permitted.cap) { - id_change = 1; + /* Only if pP' is _not_ a subset of pP, do we consider there + * has been a capability related "change of capability". In + * such cases, we need to check that the elevation of + * privilege does not go against other system constraints. + * The new Permitted set is defined below -- see (***). */ + { + kernel_cap_t working = + cap_combine(bprm->cap_permitted, + cap_intersect(bprm->cap_inheritable, + current->cap_inheritable)); + if (!cap_issubset(working, current->cap_permitted)) { + cap_raised = 1; + } } - if (id_change) { + + + + if (id_change || cap_raised) { /* We can't suid-execute if we're sharing parts of the executable */ /* or if we're being traced (or if suid execs are not allowed) */ /* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */ @@ -653,8 +658,10 @@ int prepare_binprm(struct linux_binprm *bprm) || (current->fs->count > 1) || (atomic_read(¤t->sig->count) > 1) || (current->files->count > 1)) { - if (!suser()) - return -EPERM; + if (id_change && !capable(CAP_SETUID)) + return -EPERM; + if (cap_raised && !capable(CAP_SETPCAP)) + return -EPERM; } } @@ -669,7 +676,7 @@ int prepare_binprm(struct linux_binprm *bprm) * The formula used for evolving capabilities is: * * pI' = pI - * pP' = fP | (fI & pI) + * (***) pP' = fP | (fI & pI) * pE' = pP' & fE [NB. fE is 0 or ~0] * * I=Inheritable, P=Permitted, E=Effective // p=process, f=file @@ -678,11 +685,18 @@ int prepare_binprm(struct linux_binprm *bprm) void compute_creds(struct linux_binprm *bprm) { - int new_permitted = bprm->cap_permitted.cap | - (bprm->cap_inheritable.cap & current->cap_inheritable.cap); - - current->cap_permitted.cap = new_permitted; - current->cap_effective.cap = new_permitted & bprm->cap_effective.cap; + /* For init, we want to retain the capabilities set + * in the init_task struct. Thus we skip the usual + * capability rules */ + if (current->pid != 1) { + int new_permitted = bprm->cap_permitted.cap | + (bprm->cap_inheritable.cap & + current->cap_inheritable.cap); + + current->cap_permitted.cap = new_permitted; + current->cap_effective.cap = new_permitted & + bprm->cap_effective.cap; + } /* AUD: Audit candidate if current->cap_effective is set */ diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 7555b9a6f5b6..111a2d6e0578 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -51,8 +51,11 @@ int ext2_permission (struct inode * inode, int mask) * Access is always granted for root. We now check last, * though, for BSD process accounting correctness */ - if (((mode & mask & S_IRWXO) == mask) || fsuser()) + if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE)) return 0; - else - return -EACCES; + if ((mask == S_IROTH) || + (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + if (capable(CAP_DAC_READ_SEARCH)) + return 0; + return -EACCES; } diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index de5b422eddec..f4ee2921107a 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -383,7 +383,8 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) && ((sb->u.ext2_sb.s_resuid != current->fsuid) && (sb->u.ext2_sb.s_resgid == 0 || - !in_group_p (sb->u.ext2_sb.s_resgid)) && !fsuser())) { + !in_group_p (sb->u.ext2_sb.s_resgid)) && + !capable(CAP_SYS_RESOURCE))) { unlock_super (sb); return 0; } diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 71c51809f457..d5e74cf35e30 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -144,7 +144,7 @@ static inline void remove_suid(struct inode *inode) /* was any of the uid bits set? */ mode &= inode->i_mode; - if (mode && !suser()) { + if (mode && !capable(CAP_FSETID)) { inode->i_mode &= ~mode; mark_inode_dirty(inode); } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index a48723031b6e..f0f2ca98f184 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -726,9 +726,9 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr) (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^ (inode->u.ext2_i.i_flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { - if (!fsuser()) + if (!capable(CAP_LINUX_IMMUTABLE)) goto out; - } else if ((current->fsuid != inode->i_uid) && !fsuser()) + } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) goto out; retval = inode_change_ok(inode, iattr); diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 70d4fc563473..3b58bc822536 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -39,10 +39,11 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, (inode->u.ext2_i.i_flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { /* This test looks nicer. Thanks to Pauline Middelink */ - if (!fsuser()) + if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } else - if ((current->fsuid != inode->i_uid) && !fsuser()) + if ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER)) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; @@ -70,7 +71,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, case EXT2_IOC_GETVERSION: return put_user(inode->u.ext2_i.i_version, (int *) arg); case EXT2_IOC_SETVERSION: - if ((current->fsuid != inode->i_uid) && !fsuser()) + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index cc1fd35a5db1..40a2d30ae5ea 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -631,7 +631,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) retval = -EPERM; if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto end_rmdir; @@ -725,7 +725,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry) goto end_unlink; if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; retval = -EIO; @@ -923,7 +923,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry, retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode)) goto end_rename; @@ -964,7 +964,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry, if (new_inode) { if ((new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode)) goto end_rename; diff --git a/fs/minix/namei.c b/fs/minix/namei.c index e6bf93e4b54e..3155e72e4b01 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -416,7 +416,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry) if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -482,7 +482,7 @@ repeat: } if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (de->inode != inode->i_ino) { retval = -ENOENT; @@ -641,7 +641,7 @@ start_up: retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_inode = new_dentry->d_inode; new_bh = minix_find_entry(new_dir, new_dentry->d_name.name, @@ -673,7 +673,7 @@ start_up: retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -ENOTDIR; diff --git a/fs/namei.c b/fs/namei.c index 06257ab99c63..04ebe1fd98b1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -198,8 +198,13 @@ int permission(struct inode * inode,int mask) mode >>= 6; else if (in_group_p(inode->i_gid)) mode >>= 3; - if (((mode & mask & 0007) == mask) || fsuser()) + if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE)) return 0; + /* read and search access */ + if ((mask == S_IROTH) || + (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + if (capable(CAP_DAC_READ_SEARCH)) + return 0; return -EACCES; } @@ -706,7 +711,7 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) lock_kernel(); error = -EPERM; - if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser())) + if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !capable(CAP_SYS_ADMIN))) goto out; error = -EINVAL; switch (mode & S_IFMT) { diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7acaafade1ee..66c4ecd1fafa 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -148,7 +148,7 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) if (!initialized) nfsd_init(); err = -EPERM; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { goto done; } err = -EFAULT; diff --git a/fs/open.c b/fs/open.c index 204294cc3380..6d23874f9aee 100644 --- a/fs/open.c +++ b/fs/open.c @@ -285,12 +285,14 @@ out: /* * access() needs to use the real uid/gid, not the effective uid/gid. - * We do this by temporarily setting fsuid/fsgid to the wanted values + * We do this by temporarily clearing all FS-related capabilities and + * switching the fsuid/fsgid around to the real ones. */ asmlinkage int sys_access(const char * filename, int mode) { struct dentry * dentry; int old_fsuid, old_fsgid; + kernel_cap_t old_cap; int res = -EINVAL; lock_kernel(); @@ -298,9 +300,15 @@ asmlinkage int sys_access(const char * filename, int mode) goto out; old_fsuid = current->fsuid; old_fsgid = current->fsgid; + old_cap = current->cap_effective; + current->fsuid = current->uid; current->fsgid = current->gid; + /* Clear the capabilities if we switch to a non-root user */ + if (current->uid) + cap_clear(current->cap_effective); + dentry = namei(filename); res = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -310,6 +318,7 @@ asmlinkage int sys_access(const char * filename, int mode) current->fsuid = old_fsuid; current->fsgid = old_fsgid; + current->cap_effective = old_cap; out: unlock_kernel(); return res; @@ -411,7 +420,7 @@ asmlinkage int sys_chroot(const char * filename) goto dput_and_out; error = -EPERM; - if (!fsuser()) + if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; /* exchange dentries */ @@ -833,7 +842,7 @@ asmlinkage int sys_vhangup(void) int ret = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) goto out; /* If there is a controlling tty, hang it up */ if (current->tty) diff --git a/fs/proc/array.c b/fs/proc/array.c index 79ac2c38bc34..125be772a088 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -764,6 +764,17 @@ static inline char * task_sig(struct task_struct *p, char *buffer) return buffer; } +extern inline char *task_cap(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, "CapInh:\t%016x\n" + "CapPrm:\t%016x\n" + "CapEff:\t%016x\n", + p->cap_inheritable.cap, + p->cap_permitted.cap, + p->cap_effective.cap); +} + + static int get_status(int pid, char * buffer) { char * orig = buffer; @@ -778,6 +789,7 @@ static int get_status(int pid, char * buffer) buffer = task_state(tsk, buffer); buffer = task_mem(tsk, buffer); buffer = task_sig(tsk, buffer); + buffer = task_cap(tsk, buffer); return buffer - orig; } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index b2feaeef120c..b4ca1094c4a7 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -145,8 +145,13 @@ static int standard_permission(struct inode *inode, int mask) mode >>= 6; else if (in_group_p(inode->i_gid)) mode >>= 3; - if (((mode & mask & 0007) == mask) || fsuser()) + if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE)) return 0; + /* read and search access */ + if ((mask == S_IROTH) || + (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + if (capable(CAP_DAC_READ_SEARCH)) + return 0; return -EACCES; } diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 34f9f969f24c..5597c2e6d931 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -630,7 +630,8 @@ printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid); goto out; error = -EACCES; - if (current->uid != server->mnt->mounted_uid && !suser()) + if (current->uid != server->mnt->mounted_uid && + !capable(CAP_SYS_ADMIN)) goto out; error = -EBADF; diff --git a/fs/super.c b/fs/super.c index 0433dd251d2d..b28b5f0b605b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -743,7 +743,7 @@ asmlinkage int sys_umount(char * name) struct dentry * dentry; int retval; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); @@ -985,7 +985,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, struct file dummy; /* allows read-write or read-only flag */ lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 270cfe637524..60b50720aae7 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -419,7 +419,7 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry) if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -484,7 +484,7 @@ repeat: } if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (de->inode != inode->i_ino) { retval = -ENOENT; @@ -643,7 +643,7 @@ start_up: retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_inode = new_dentry->d_inode; new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name, @@ -675,7 +675,7 @@ start_up: retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -ENOTDIR; diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index be72a9cb48ae..7b549fd963fb 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -350,14 +350,14 @@ static int umsdos_rename_f( Printk (("ret %d ",ret)); if (ret == 0){ /* check sticky bit on old_dir */ - if ( !(old_dir->i_mode & S_ISVTX) || fsuser() || + if ( !(old_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || current->fsuid == old_info.entry.uid || current->fsuid == old_dir->i_uid ) { /* Does new_name already exist? */ PRINTK(("new findentry ")); ret = umsdos_findentry(new_dir,&new_info,0); if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ - !(new_dir->i_mode & S_ISVTX) || fsuser() || + !(new_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || current->fsuid == new_info.entry.uid || current->fsuid == new_dir->i_uid ) { PRINTK (("new newentry ")); @@ -933,7 +933,7 @@ int UMSDOS_rmdir( umsdos_real_lookup (dir, tdentry); /* fill inode part */ Printk (("isempty %d i_count %d ",empty,sdir->i_count)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || fsuser() || + if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || current->fsuid == sdir->i_uid || current->fsuid == dir->i_uid ) { if (empty == 1){ @@ -1024,7 +1024,7 @@ int UMSDOS_unlink ( if (ret == 0){ Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || fsuser() || + if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) || current->fsuid == info.entry.uid || current->fsuid == dir->i_uid ) { if (info.entry.flags & UMSDOS_HLINK){ diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h index bef18652908a..e8de11f12731 100644 --- a/include/asm-alpha/ide.h +++ b/include/asm-alpha/ide.h @@ -19,7 +19,7 @@ typedef unsigned short ide_ioreg_t; #define MAX_HWIFS 4 #endif -#define ide_sti() sti() +#define ide__sti() __sti() static __inline__ int ide_default_irq(ide_ioreg_t base) { diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h index 8ad19c2f4df0..0d4ab6b214c7 100644 --- a/include/asm-alpha/mmu_context.h +++ b/include/asm-alpha/mmu_context.h @@ -116,5 +116,17 @@ extern inline void init_new_context(struct mm_struct *mm) #define destroy_context(mm) do { } while(0) +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + * Ideally this would be an extern inline function, but reload_context + * is declared in pgtable.h, which includes this file. :-( + */ +#define activate_context(tsk) \ + do { \ + get_mmu_context(tsk); \ + reload_context(tsk); \ + } while (0) + #endif diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h index 3710c2911210..2ead7b36a13a 100644 --- a/include/asm-arm/ide.h +++ b/include/asm-arm/ide.h @@ -19,7 +19,7 @@ typedef unsigned long ide_ioreg_t; #define MAX_HWIFS 4 #endif -#define ide_sti() sti() +#define ide__sti() __sti() #include diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h index 7325fbaa49f7..f6e4c3e330e0 100644 --- a/include/asm-arm/mmu_context.h +++ b/include/asm-arm/mmu_context.h @@ -13,5 +13,6 @@ #define init_new_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0) +#define activate_context(tsk) do { } while(0) #endif diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h index e61802fec61e..a6d1fc868e9f 100644 --- a/include/asm-i386/ide.h +++ b/include/asm-i386/ide.h @@ -19,7 +19,7 @@ typedef unsigned short ide_ioreg_t; #define MAX_HWIFS 6 #endif -#define ide_sti() sti() +#define ide__sti() __sti() static __inline__ int ide_default_irq(ide_ioreg_t base) { diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h index 01b8bfcbacbd..e8b812e2f83d 100644 --- a/include/asm-i386/mmu_context.h +++ b/include/asm-i386/mmu_context.h @@ -8,5 +8,6 @@ #define init_new_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0) +#define activate_context(tsk) do { } while(0) #endif diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index 48c586d6c770..e6a42b227944 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -3,6 +3,10 @@ #ifndef __SMP__ +#define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ + +#if (DEBUG_SPINLOCKS < 1) + /* * Your basic spinlocks, allowing only a single CPU anywhere */ @@ -11,7 +15,7 @@ typedef struct { } spinlock_t; #define spin_lock_init(lock) do { } while(0) #define spin_lock(lock) do { } while(0) -#define spin_trylock(lock) do { } while(0) +#define spin_trylock(lock) (1) #define spin_unlock_wait(lock) do { } while(0) #define spin_unlock(lock) do { } while(0) #define spin_lock_irq(lock) cli() @@ -22,6 +26,52 @@ typedef struct { } spinlock_t; #define spin_unlock_irqrestore(lock, flags) \ restore_flags(flags) +#elif (DEBUG_SPINLOCKS < 2) + +typedef struct { + volatile unsigned int lock; +} spinlock_t; +#define SPIN_LOCK_UNLOCKED { 0 } + +#define spin_lock_init(x) do { (x)->lock = 0; } while (0) +#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) + +#define spin_lock(x) do { (x)->lock = 1; } while (0) +#define spin_unlock_wait(x) do { } while (0) +#define spin_unlock(x) do { (x)->lock = 0; } while (0) +#define spin_lock_irq(x) do { cli(); spin_lock(x); } while (0) +#define spin_unlock_irq(x) do { spin_unlock(x); sti(); } while (0) + +#define spin_lock_irqsave(x, flags) \ + do { save_flags(flags); spin_lock_irq(x); } while (0) +#define spin_unlock_irqrestore(x, flags) \ + do { spin_unlock(x); restore_flags(flags); } while (0) + +#else /* (DEBUG_SPINLOCKS >= 2) */ + +typedef struct { + volatile unsigned int lock; + volatile unsigned int babble; + const char *module; +} spinlock_t; +#define SPIN_LOCK_UNLOCKED { 0, 25, __BASE_FILE__ } + +#include + +#define spin_lock_init(x) do { (x)->lock = 0; } while (0) +#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) + +#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0) +#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0) +#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s: spin_unlock(%s:%p) not locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0) +#define spin_lock_irq(x) do {cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock_irq(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0) +#define spin_unlock_irq(x) do {cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; sti();} while (0) + +#define spin_lock_irqsave(x,flags) do {save_flags(flags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock_irqsave(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0) +#define spin_unlock_irqrestore(x,flags) do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s: spin_unlock_irqrestore(%s:%p) not locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(flags);} while (0) + +#endif /* DEBUG_SPINLOCKS */ + /* * Read-write spinlocks, allowing multiple readers * but only one writer. @@ -53,13 +103,10 @@ typedef struct { } rwlock_t; #define write_unlock_irqrestore(lock, flags) \ restore_flags(flags) -#else +#else /* __SMP__ */ /* - * Simple spin lock operations. There are two variants, one clears IRQ's - * on the local processor, one does not. - * - * We make no fairness assumptions. They have a cost. + * Your basic spinlocks, allowing only a single CPU anywhere */ typedef struct { @@ -69,6 +116,13 @@ typedef struct { #define SPIN_LOCK_UNLOCKED { 0 } #define spin_lock_init(x) do { (x)->lock = 0; } while(0) +/* + * Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ + #define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock) typedef struct { unsigned long a[100]; } __dummy_lock_t; @@ -176,5 +230,5 @@ typedef struct { #define write_unlock_irqrestore(lock, flags) \ do { write_unlock(lock); __restore_flags(flags); } while (0) -#endif /* SMP */ +#endif /* __SMP__ */ #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 3ac10a193a86..018f6f0f5407 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -189,6 +189,8 @@ #define __NR_pwrite 181 #define __NR_chown 182 #define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 /* user-visible error numbers are in the range -1 - -122: see */ diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h index 0a0222ac5b1c..a69ef5b180ec 100644 --- a/include/asm-m68k/ide.h +++ b/include/asm-m68k/ide.h @@ -424,17 +424,17 @@ static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, * works. (Roman) */ #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) -#define ide_sti() \ +#define ide__sti() \ do { \ - if (!in_interrupt()) sti(); \ + if (!in_interrupt()) __sti(); \ } while(0) #elif defined(CONFIG_ATARI) -#define ide_sti() \ +#define ide__sti() \ do { \ if (!MACH_IS_ATARI || !in_interrupt()) sti(); \ } while(0) #else /* !defined(CONFIG_ATARI) */ -#define ide_sti() sti() +#define ide__sti() __sti() #endif #endif /* __KERNEL__ */ diff --git a/include/asm-m68k/mmu_context.h b/include/asm-m68k/mmu_context.h index 853ce4b71027..4850dd40415e 100644 --- a/include/asm-m68k/mmu_context.h +++ b/include/asm-m68k/mmu_context.h @@ -8,5 +8,6 @@ #define init_new_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0) +#define activate_context(tsk) do { } while(0) #endif diff --git a/include/asm-mips/ide.h b/include/asm-mips/ide.h index bda27206dea5..733661667910 100644 --- a/include/asm-mips/ide.h +++ b/include/asm-mips/ide.h @@ -19,7 +19,7 @@ typedef unsigned short ide_ioreg_t; #define MAX_HWIFS 4 #endif -#define ide_sti() sti() +#define ide__sti() __sti() static __inline__ int ide_default_irq(ide_ioreg_t base) { diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index 87b12792e44c..5010f4d349ce 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -62,4 +62,14 @@ extern inline void destroy_context(struct mm_struct *mm) mm->context = 0; } +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +extern inline activate_context(struct task_struct *tsk) +{ + get_mmu_context(tsk); + /* XXX here we presumably need to set some cpu register - paulus. */ +} + #endif /* __ASM_MIPS_MMU_CONTEXT_H */ diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h index efbd4b363cdd..d9e25bacebbb 100644 --- a/include/asm-ppc/ide.h +++ b/include/asm-ppc/ide.h @@ -26,7 +26,7 @@ #define SUPPORT_VLB_SYNC 0 -#define ide_sti() sti() +#define ide__sti() __sti() typedef unsigned int ide_ioreg_t; void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq); diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index d715f4ca4d67..0f06f16fe335 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -22,9 +22,20 @@ #ifdef CONFIG_8xx #define NO_CONTEXT 16 #define LAST_CONTEXT 15 +#define MUNGE_CONTEXT(n) (n) + #else + +/* PPC 6xx, 7xx CPUs */ #define NO_CONTEXT 0 #define LAST_CONTEXT 0xfffff + +/* + * Allocating context numbers this way tends to spread out + * the entries in the hash table better than a simple linear + * allocation. + */ +#define MUNGE_CONTEXT(n) (((n) * 897) & LAST_CONTEXT) #endif extern int next_mmu_context; @@ -36,17 +47,6 @@ extern void set_context(int context); #define set_context(context) do { } while (0) #endif -#ifndef CONFIG_8xx -/* - * Allocating context numbers this way tends to spread out - * the entries in the hash table better than a simple linear - * allocation. - */ -#define MUNGE_CONTEXT(n) (((n) * 897) & LAST_CONTEXT) -#else -#define MUNGE_CONTEXT(n) (n) -#endif - /* * Get a new mmu context for task tsk if necessary. */ @@ -57,8 +57,6 @@ do { \ if (next_mmu_context == LAST_CONTEXT) \ mmu_context_overflow(); \ mm->context = MUNGE_CONTEXT(++next_mmu_context);\ - if ( tsk == current ) \ - set_context(mm->context); \ } \ } while (0) @@ -70,11 +68,17 @@ do { \ /* * We're finished using the context for an address space. */ -#ifdef CONFIG_8xx #define destroy_context(mm) ((mm)->context = NO_CONTEXT) -#else -#define destroy_context(mm) do { } while (0) -#endif + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +extern inline void activate_context(struct task_struct *tsk) +{ + get_mmu_context(tsk); + set_context(tsk->mm->context); +} /* * compute the vsid from the context and segment diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h index d6ac7e9229df..d73b71f94727 100644 --- a/include/asm-sparc/mmu_context.h +++ b/include/asm-sparc/mmu_context.h @@ -22,4 +22,11 @@ BTFIXUPDEF_CALL(void, destroy_context, struct mm_struct *) #define destroy_context(mm) BTFIXUP_CALL(destroy_context)(mm) +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + * XXX this presumably needs a sensible implementation - paulus. + */ +#define activate_context(tsk) do { } while(0) + #endif /* !(__SPARC_MMU_CONTEXT_H) */ diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h index f72c264c8b0c..acd59330303e 100644 --- a/include/asm-sparc64/ide.h +++ b/include/asm-sparc64/ide.h @@ -15,7 +15,7 @@ typedef unsigned long ide_ioreg_t; #undef MAX_HWIFS #define MAX_HWIFS 2 -#define ide_sti() sti() +#define ide__sti() __sti() static __inline__ int ide_default_irq(ide_ioreg_t base) { @@ -38,7 +38,7 @@ static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int for ( ; i < 10; i++) *p++ = 0; /* PCI code needs to figure out this. */ - if(irq != NULL) + if (irq != NULL) *irq = 0; } diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index b92481dd54f7..44209a120575 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -72,6 +72,12 @@ extern __inline__ void get_mmu_context(struct task_struct *tsk) : "o4"); } +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +#define activate_context(tsk) get_mmu_context(tsk) + #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_MMU_CONTEXT_H) */ diff --git a/include/linux/blk.h b/include/linux/blk.h index 5101379f49ef..d7dc45db6104 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -95,7 +95,7 @@ void initrd_init(void); #endif #define RO_IOCTLS(dev,where) \ - case BLKROSET: { int __val; if (!suser()) return -EACCES; \ + case BLKROSET: { int __val; if (!capable(CAP_SYS_ADMIN)) return -EACCES; \ if (get_user(__val, (int *)(where))) return -EFAULT; \ set_device_ro((dev),__val); return 0; } \ case BLKROGET: { int __val = (is_read_only(dev) != 0) ; \ @@ -411,14 +411,20 @@ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); #ifdef IDE_DRIVER void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) { - struct request *req = hwgroup->rq; + int nsect; + struct buffer_head *bh; + struct request *req; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock,flags); + req = hwgroup->rq; #else static void end_request(int uptodate) { - struct request *req = CURRENT; -#endif /* IDE_DRIVER */ - struct buffer_head * bh; int nsect; + struct buffer_head *bh; + struct request *req = CURRENT; +#endif /* IDE_DRIVER */ req->errors = 0; if (!uptodate) { printk("end_request: I/O error, dev %s, sector %lu\n", @@ -443,6 +449,9 @@ static void end_request(int uptodate) { printk("end_request: buffer-list destroyed\n"); } req->buffer = bh->b_data; +#ifdef IDE_DRIVER + spin_unlock_irqrestore(&io_request_lock,flags); +#endif /* IDE_DRIVER */ return; } } @@ -461,6 +470,9 @@ static void end_request(int uptodate) { up(req->sem); req->rq_status = RQ_INACTIVE; wake_up(&wait_for_request); +#ifdef IDE_DRIVER + spin_unlock_irqrestore(&io_request_lock,flags); +#endif /* IDE_DRIVER */ } #endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */ #endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */ diff --git a/include/linux/capability.h b/include/linux/capability.h index db737e55f042..a0342601f2f8 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -17,19 +17,33 @@ kernel might be somewhat backwards compatible, but don't bet on it. */ +/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to + a set of three capability sets. The transposition of 3*the + following structure to such a composite is better handled in a user + library since the draft standard requires the use of malloc/free + etc.. */ + #define _LINUX_CAPABILITY_VERSION 0x19980330 -typedef struct _user_cap_struct { +typedef struct __user_cap_header_struct { __u32 version; - __u32 size; - __u8 cap[1]; -} *cap_t; - + int pid; +} *cap_user_header_t; + +typedef struct __user_cap_data_struct { + __u32 effective; + __u32 permitted; + __u32 inheritable; +} *cap_user_data_t; + #ifdef __KERNEL__ typedef struct kernel_cap_struct { - int cap; + __u32 cap; } kernel_cap_t; + +#define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) +#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) #endif @@ -46,13 +60,13 @@ typedef struct kernel_cap_struct { /* Override all DAC access, including ACL execute access if [_POSIX_ACL] is defined. Excluding DAC access covered by - CAP_LINUX_IMMUTABLE */ + CAP_LINUX_IMMUTABLE. */ #define CAP_DAC_OVERRIDE 1 /* Overrides all DAC restrictions regarding read and search on files and directories, including ACL restrictions if [_POSIX_ACL] is - defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE */ + defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ #define CAP_DAC_READ_SEARCH 2 @@ -82,10 +96,13 @@ typedef struct kernel_cap_struct { #define CAP_KILL 5 /* Allows setgid(2) manipulation */ +/* Allows setgroups(2) */ +/* Allows forged gids on socket credentials passing. */ #define CAP_SETGID 6 -/* Allows setuid(2) manipulation */ +/* Allows set*uid(2) manipulation (including fsuid). */ +/* Allows forged pids on socket credentials passing. */ #define CAP_SETUID 7 @@ -112,9 +129,17 @@ typedef struct kernel_cap_struct { #define CAP_NET_BROADCAST 11 /* Allow interface configuration */ -/* Allow configuring of firewall stuff */ +/* Allow administration of IP firewall, masquerading and accounting */ /* Allow setting debug option on sockets */ /* Allow modification of routing tables */ +/* Allow setting arbitrary process / process group ownership on + sockets */ +/* Allow binding to any address for transparent proxying */ +/* Allow setting TOS (type of service) */ +/* Allow setting promiscuous mode */ +/* Allow clearing driver statistics */ +/* Allow multicasting */ +/* Allow read/write of device-specific registers */ #define CAP_NET_ADMIN 12 @@ -123,7 +148,9 @@ typedef struct kernel_cap_struct { #define CAP_NET_RAW 13 -/* Allow locking of segments in memory */ +/* Allow locking of shared memory segments */ +/* Allow mlock and mlockall (which doesn't really have anything to do + with IPC) */ #define CAP_IPC_LOCK 14 @@ -153,9 +180,42 @@ typedef struct kernel_cap_struct { /* Allow configuration of the secure attention key */ /* Allow administration of the random device */ -/* Allow device administration */ +/* Allow device administration (mknod)*/ /* Allow examination and configuration of disk quotas */ -/* System Admin functions: mount et al */ +/* Allow configuring the kernel's syslog (printk behaviour) */ +/* Allow sending a signal to any process */ +/* Allow setting the domainname */ +/* Allow setting the hostname */ +/* Allow calling bdflush() */ +/* Allow mount() and umount(), setting up new smb connection */ +/* Allow some autofs root ioctls */ +/* Allow nfsservctl */ +/* Allow VM86_REQUEST_IRQ */ +/* Allow to read/write pci config on alpha */ +/* Allow irix_prctl on mips (setstacksize) */ +/* Allow flushing all cache on m68k (sys_cacheflush) */ +/* Allow removing semaphores */ +/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + and shared memory */ +/* Allow locking/unlocking of shared memory segment */ +/* Allow turning swap on/off */ +/* Allow forged pids on socket credentials passing */ +/* Allow setting readahead and flushing buffers on block devices */ +/* Allow setting geometry in floppy driver */ +/* Allow turning DMA on/off in xd driver */ +/* Allow administration of md devices (mostly the above, but some + extra ioctls) */ +/* Allow tuning the ide driver */ +/* Allow access to the nvram device */ +/* Allow administration of apm_bios, serial and bttv (TV) device */ +/* Allow manufacturer commands in isdn CAPI support driver */ +/* Allow reading non-standardized portions of pci configuration space */ +/* Allow DDI debug ioctl on sbpcd driver */ +/* Allow setting up serial ports */ +/* Allow sending raw qic-117 commands */ +/* Allow enabling/disabling tagged queuing on SCSI controllers and sending + arbitrary SCSI commands */ +/* Allow setting encryption key on loopback filesystem */ #define CAP_SYS_ADMIN 21 @@ -163,19 +223,34 @@ typedef struct kernel_cap_struct { #define CAP_SYS_BOOT 22 -/* Allow use of renice() on others, and raising of priority */ +/* Allow raising priority and setting priority on other (different + UID) processes */ +/* Allow use of FIFO and round-robin (realtime) scheduling on own + processes and setting the scheduling algorithm used by another + process. */ #define CAP_SYS_NICE 23 -/* Override resource limits */ +/* Override resource limits. Set resource limits. */ +/* Override quota limits. */ +/* Override reserved space on ext2 filesystem */ +/* NOTE: ext2 honors fsuid when checking for resource overrides, so + you can override using fsuid too */ +/* Override size restrictions on IPC message queues */ +/* Allow more than 64hz interrupts from the real-time clock */ +/* Override max number of consoles on console allocation */ +/* Override max number of keymaps */ #define CAP_SYS_RESOURCE 24 /* Allow manipulation of system clock */ +/* Allow irix_stime on mips */ +/* Allow setting the real-time clock */ #define CAP_SYS_TIME 25 /* Allow configuration of tty devices */ +/* Allow vhangup() of tty */ #define CAP_SYS_TTY_CONFIG 26 @@ -187,17 +262,48 @@ typedef struct kernel_cap_struct { #define CAP_EMPTY_SET { 0 } #define CAP_FULL_SET { ~0 } +#define CAP_INIT_EFF_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } +#define CAP_INIT_INH_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } #define CAP_TO_MASK(x) (1 << (x)) -#define cap_raise(c, flag) (c.cap |= CAP_TO_MASK(flag)) -#define cap_lower(c, flag) (c.cap &= ~CAP_TO_MASK(flag)) -#define cap_raised(c, flag) (c.cap & CAP_TO_MASK(flag)) - -#define cap_isclear(c) (!c.cap) - -#define cap_copy(dest,src) do { (dest).cap = (src).cap; } while(0) -#define cap_clear(c) do { c.cap = 0; } while(0) -#define cap_set_full(c) do { c.cap = ~0; } while(0) +#define cap_raise(c, flag) ((c).cap |= CAP_TO_MASK(flag)) +#define cap_lower(c, flag) ((c).cap &= ~CAP_TO_MASK(flag)) +#define cap_raised(c, flag) ((c).cap & CAP_TO_MASK(flag)) + +static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) +{ + kernel_cap_t dest; + dest.cap = a.cap | b.cap; + return dest; +} + +static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b) +{ + kernel_cap_t dest; + dest.cap = a.cap & b.cap; + return dest; +} + +static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop) +{ + kernel_cap_t dest; + dest.cap = a.cap & ~drop.cap; + return dest; +} + +static inline kernel_cap_t cap_invert(kernel_cap_t c) +{ + kernel_cap_t dest; + dest.cap = ~c.cap; + return dest; +} + +#define cap_isclear(c) (!(c).cap) +#define cap_issubset(a,set) (!((a).cap & ~(set).cap)) + +#define cap_clear(c) do { (c).cap = 0; } while(0) +#define cap_set_full(c) do { (c).cap = ~0; } while(0) +#define cap_mask(c,mask) do { (c).cap &= (mask).cap; } while(0) #define cap_is_fs_cap(c) ((c) & CAP_FS_MASK) diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index 9be5bd1b1c61..bb343ac2e057 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -45,7 +45,7 @@ #define WIN_VERIFY 0x40 #define WIN_FORMAT 0x50 #define WIN_INIT 0x60 -#define WIN_SEEK 0x70 +#define WIN_SEEK 0x70 #define WIN_DIAGNOSE 0x90 #define WIN_SPECIFY 0x91 /* set drive geometry translation */ #define WIN_SETIDLE1 0xE3 @@ -101,12 +101,13 @@ struct hd_geometry { #define HDIO_GETGEO 0x0301 /* get device geometry */ #define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ #define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ -#define HDIO_GET_IDENTITY 0x0307 /* get IDE identification info */ -#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ -#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ +#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */ +#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ +#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ #define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ #define HDIO_GET_DMA 0x030b /* get use-dma flag */ #define HDIO_GET_NICE 0x030c /* get nice flags */ +#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ #define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ diff --git a/include/linux/lp.h b/include/linux/lp.h index ba2e34f07c47..b50c6b434591 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -20,11 +20,14 @@ #define LP_EXIST 0x0001 #define LP_SELEC 0x0002 #define LP_BUSY 0x0004 +#define LP_BUSY_BIT_POS 2 #define LP_OFFL 0x0008 #define LP_NOPA 0x0010 #define LP_ERR 0x0020 #define LP_ABORT 0x0040 +#ifdef LP_NEED_CAREFUL #define LP_CAREFUL 0x0080 +#endif #define LP_ABORTOPEN 0x0100 /* timeout for each character. This is relative to bus cycles -- it @@ -67,14 +70,18 @@ or 0 for polling (no IRQ) */ #define LPGETIRQ 0x0606 /* get the current IRQ number */ #define LPWAIT 0x0608 /* corresponds to LP_INIT_WAIT */ +#ifdef LP_NEED_CAREFUL #define LPCAREFUL 0x0609 /* call with TRUE arg to require out-of-paper, off- line, and error indicators good on all writes, FALSE to ignore them. Default is ignore. */ +#endif #define LPABORTOPEN 0x060a /* call with TRUE arg to abort open() on error, FALSE to ignore error. Default is ignore. */ #define LPGETSTATUS 0x060b /* return LP_S(minor) */ #define LPRESET 0x060c /* reset printer */ +#ifdef LP_STATS #define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */ +#endif #define LPGETFLAGS 0x060e /* get status flags */ /* timeout for printk'ing a timeout, in jiffies (100ths of a second). @@ -90,11 +97,14 @@ #define LP_WAIT(minor) lp_table[(minor)].wait /* strobe wait */ #define LP_IRQ(minor) lp_table[(minor)].dev->port->irq /* interrupt # */ /* 0 means polled */ +#ifdef LP_STATS #define LP_STAT(minor) lp_table[(minor)].stats /* statistics area */ +#endif #define LP_BUFFER_SIZE 256 #define LP_BASE(x) lp_table[(x)].dev->port->base +#ifdef LP_STATS struct lp_stats { unsigned long chars; unsigned long sleeps; @@ -103,6 +113,7 @@ struct lp_stats { unsigned int meanwait; unsigned int mdev; }; +#endif struct lp_struct { struct pardevice *dev; @@ -111,10 +122,13 @@ struct lp_struct { unsigned int time; unsigned int wait; char *lp_buffer; +#ifdef LP_STATS unsigned int lastcall; unsigned int runchars; - unsigned int waittime; struct lp_stats stats; +#endif + struct wait_queue *wait_q; + unsigned int last_error; }; /* @@ -160,7 +174,7 @@ struct lp_struct { */ #define LP_DELAY 50 -#define LP_POLLING(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) +#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) #define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL) /* diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 96e85496a91a..1cd2905dea69 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -379,7 +379,6 @@ extern struct inode_operations proc_dir_inode_operations; extern struct inode_operations proc_file_inode_operations; extern struct inode_operations proc_net_inode_operations; extern struct inode_operations proc_netdir_inode_operations; -extern struct inode_operations proc_scsi_inode_operations; extern struct inode_operations proc_openprom_inode_operations; extern struct inode_operations proc_mem_inode_operations; extern struct inode_operations proc_sys_inode_operations; @@ -396,8 +395,6 @@ extern struct inode_operations proc_ringbuf_inode_operations; extern struct inode_operations proc_omirr_inode_operations; extern struct inode_operations proc_ppc_htab_inode_operations; -#endif - /* * generic.c */ @@ -416,3 +413,5 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver); * proc_devtree.c */ extern void proc_device_tree_init(void); + +#endif /* _LINUX_PROC_FS_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index ceeea5d427cb..a1b2f3559f17 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -354,7 +354,7 @@ struct task_struct { /* process credentials */ \ /* uid etc */ 0,0,0,0,0,0,0,0, \ /* suppl grps*/ 0, {0,}, \ -/* caps */ CAP_FULL_SET, CAP_FULL_SET, CAP_FULL_SET, \ +/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ /* rlimits */ INIT_RLIMITS, \ /* math */ 0, \ /* comm */ "swapper", \ diff --git a/ipc/msg.c b/ipc/msg.c index 30fe31239804..e505bcc01684 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -477,9 +477,10 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) case IPC_SET: err = -EPERM; if (current->euid != ipcp->cuid && - current->euid != ipcp->uid && !suser()) + current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) + /* We _could_ check for CAP_CHOWN above, but we don't */ goto out; - if (tbuf.msg_qbytes > MSGMNB && !suser()) + if (tbuf.msg_qbytes > MSGMNB && !capable(CAP_SYS_RESOURCE)) goto out; msq->msg_qbytes = tbuf.msg_qbytes; ipcp->uid = tbuf.msg_perm.uid; @@ -492,7 +493,7 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) case IPC_RMID: err = -EPERM; if (current->euid != ipcp->cuid && - current->euid != ipcp->uid && !suser()) + current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) goto out; freeque (id); diff --git a/ipc/sem.c b/ipc/sem.c index 8e5be61d291f..0ab578584697 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -482,7 +482,8 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) goto out; break; case IPC_RMID: - if (current->euid == ipcp->cuid || current->euid == ipcp->uid || suser()) { + if (current->euid == ipcp->cuid || + current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) { freeary (id); err = 0; goto out; @@ -540,7 +541,8 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) update_queue(sma); break; case IPC_SET: - if (current->euid == ipcp->cuid || current->euid == ipcp->uid || suser()) { + if (current->euid == ipcp->cuid || + current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) { ipcp->uid = tbuf.sem_perm.uid; ipcp->gid = tbuf.sem_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) diff --git a/ipc/shm.c b/ipc/shm.c index 09b69c4a3388..0962be88279e 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -306,7 +306,7 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) switch (cmd) { case SHM_UNLOCK: err = -EPERM; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) goto out; err = -EINVAL; if (!(ipcp->mode & SHM_LOCKED)) @@ -318,7 +318,7 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ err = -EPERM; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) goto out; err = -EINVAL; if (ipcp->mode & SHM_LOCKED) @@ -347,7 +347,8 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) break; case IPC_SET: if (current->euid == shp->shm_perm.uid || - current->euid == shp->shm_perm.cuid || suser()) { + current->euid == shp->shm_perm.cuid || + capable(CAP_SYS_ADMIN)) { ipcp->uid = tbuf.shm_perm.uid; ipcp->gid = tbuf.shm_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) @@ -359,7 +360,8 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) goto out; case IPC_RMID: if (current->euid == shp->shm_perm.uid || - current->euid == shp->shm_perm.cuid || suser()) { + current->euid == shp->shm_perm.cuid || + capable(CAP_SYS_ADMIN)) { shp->shm_perm.mode |= SHM_DEST; if (shp->shm_nattch <= 0) killseg (id); diff --git a/ipc/util.c b/ipc/util.c index eacea2b6239d..fe13f8676553 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -47,8 +47,10 @@ int ipcperms (struct ipc_perm *ipcp, short flag) else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) granted_mode >>= 3; /* is there some bit set in requested_mode but not in granted_mode? */ - if ((requested_mode & ~granted_mode & 0007) && !suser()) + if ((requested_mode & ~granted_mode & 0007) && + !capable(CAP_IPC_OWNER)) return -1; + return 0; } diff --git a/kernel/Makefile b/kernel/Makefile index 4e0a1d87d8f5..abd520d4499d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -13,7 +13,7 @@ O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ - sysctl.o acct.o + sysctl.o acct.o capability.o OX_OBJS += signal.o diff --git a/kernel/acct.c b/kernel/acct.c index 4229b9ebfb5c..6a00f3571177 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -119,7 +119,7 @@ asmlinkage int sys_acct(const char *name) int error = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_PACCT)) goto out; if (name == (char *)NULL) { diff --git a/kernel/capability.c b/kernel/capability.c new file mode 100644 index 000000000000..ddbfaa87b6d7 --- /dev/null +++ b/kernel/capability.c @@ -0,0 +1,252 @@ +/* + * linux/kernel/capability.c + * + * Copyright (C) 1997 Andrew Main + * Integrated into 2.1.97+, Andrew G. Morgan + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static inline void cap_fromuser(kernel_cap_t *k, __u32 *u) +{ + copy_from_user(k, u, sizeof(*k)); +} + + +static inline void cap_touser(__u32 *u, const kernel_cap_t *k) +{ + copy_to_user(u, k, sizeof(*k)); +} + +#ifdef __SMP__ +static spinlock_t task_capability_lock; +#endif + +/* + * For sys_getproccap() and sys_setproccap(), any of the three + * capability set pointers may be NULL -- indicating that that set is + * uninteresting and/or not to be changed. + */ + +asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t data) +{ + int error = -EINVAL, pid; + __u32 version; + struct task_struct *target; + + if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { + /* not large enough for current header so indicate error */ + if (access_ok(VERIFY_WRITE, &header->version, + sizeof(header->version))) { + return error; + } + goto all_done; + } + + copy_from_user(&version, &header->version, sizeof(header->version)); + if (version != _LINUX_CAPABILITY_VERSION) { + /* if enough space for kernel version, write that */ + + all_done: + version = _LINUX_CAPABILITY_VERSION; + copy_to_user(&header->version, &version, + sizeof(header->version)); + return error; + } + + if (!access_ok(VERIFY_WRITE, data, sizeof(*data))) { + return error; + } + + copy_from_user(&pid, &header->pid, sizeof(header->pid)); + if (pid < 0) { + return error; + } + + spin_lock(&task_capability_lock); + + if (pid && pid != current->pid) { + read_lock(&tasklist_lock); + target = find_task_by_pid(pid); /* identify target of query */ + if (!target) { + error = -ESRCH; + goto out; + } + } else { + target = current; + } + + cap_touser(&data->permitted, &target->cap_permitted); + cap_touser(&data->inheritable, &target->cap_inheritable); + cap_touser(&data->effective, &target->cap_effective); + + error = 0; + +out: + if (target != current) { + read_unlock(&tasklist_lock); + } + spin_unlock(&task_capability_lock); + return error; +} + +/* set capabilities for all processes in a given process group */ + +static void cap_set_pg(int pgrp, + kernel_cap_t *effective, + kernel_cap_t *inheritable, + kernel_cap_t *permitted) +{ + struct task_struct *target; + + /* FIXME: do we need to have a write lock here..? */ + read_lock(&tasklist_lock); + for_each_task(target) { + if (target->pgrp != pgrp) + continue; + target->cap_effective = *effective; + target->cap_inheritable = *inheritable; + target->cap_permitted = *permitted; + } + read_unlock(&tasklist_lock); +} + +/* set capabilities for all processes other than 1 and self */ + +static void cap_set_all(kernel_cap_t *effective, + kernel_cap_t *inheritable, + kernel_cap_t *permitted) +{ + struct task_struct *target; + + /* FIXME: do we need to have a write lock here..? */ + read_lock(&tasklist_lock); + /* ALL means everyone other than self or 'init' */ + for_each_task(target) { + if (target == current || target->pid == 1) + continue; + target->cap_effective = *effective; + target->cap_inheritable = *inheritable; + target->cap_permitted = *permitted; + } + read_unlock(&tasklist_lock); +} + +/* + * The restrictions on setting capabilities are specified as: + * + * [pid is for the 'target' task. 'current' is the calling task.] + * + * I: any raised capabilities must be a subset of the (old current) Permitted + * P: any raised capabilities must be a subset of the (old current) permitted + * E: must be set to a subset of (new target) Permitted + */ + +asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) +{ + kernel_cap_t inheritable, permitted, effective; + __u32 version; + struct task_struct *target; + int error = -EINVAL, pid; + + if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { + /* not large enough for current header so indicate error */ + if (!access_ok(VERIFY_WRITE, &header->version, + sizeof(header->version))) { + return error; + } + goto all_done; + } + + copy_from_user(&version, &header->version, sizeof(header->version)); + if (version != _LINUX_CAPABILITY_VERSION) { + + all_done: + version = _LINUX_CAPABILITY_VERSION; + copy_to_user(&header->version, &version, + sizeof(header->version)); + return error; + } + + if (!access_ok(VERIFY_READ, data, sizeof(*data))) { + return error; + } + + /* may want to set other processes at some point -- for now demand 0 */ + copy_from_user(&pid, &header->pid, sizeof(pid)); + + error = -EPERM; + if (pid && !capable(CAP_SETPCAP)) + return error; + + spin_lock(&task_capability_lock); + + if (pid > 0 && pid != current->pid) { + read_lock(&tasklist_lock); + target = find_task_by_pid(pid); /* identify target of query */ + if (!target) { + error = -ESRCH; + goto out; + } + } else { + target = current; + } + + /* copy from userspace */ + cap_fromuser(&effective, &data->effective); + cap_fromuser(&inheritable, &data->inheritable); + cap_fromuser(&permitted, &data->permitted); + + /* verify restrictions on target's new Inheritable set */ + if (!cap_issubset(inheritable, + cap_combine(target->cap_inheritable, + current->cap_permitted))) { + goto out; + } + + /* verify restrictions on target's new Permitted set */ + if (!cap_issubset(permitted, + cap_combine(target->cap_permitted, + current->cap_permitted))) { + goto out; + } + + /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ + if (!cap_issubset(effective, permitted)) { + goto out; + } + + /* having verified that the proposed changes are legal, + we now put them into effect. */ + error = 0; + + if (pid < 0) { + if (pid == -1) /* all procs other than current and init */ + cap_set_all(&effective, &inheritable, &permitted); + + else /* all procs in process group */ + cap_set_pg(-pid, &effective, &inheritable, &permitted); + goto spin_out; + } else { + /* FIXME: do we need to have a write lock here..? */ + target->cap_effective = effective; + target->cap_inheritable = inheritable; + target->cap_permitted = permitted; + } + +out: + if (target != current) { + read_unlock(&tasklist_lock); + } +spin_out: + spin_unlock(&task_capability_lock); + return error; +} diff --git a/kernel/fork.c b/kernel/fork.c index 88199cae1536..c29c52eceec0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -56,9 +56,7 @@ static struct uid_taskcount { int task_count; } *uidhash[UIDHASH_SZ]; -#ifdef __SMP__ -static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; -#endif +spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; kmem_cache_t *uid_cachep; @@ -154,10 +152,8 @@ static inline int find_empty_process(void) return -EAGAIN; } -#ifdef __SMP__ /* Protects next_safe and last_pid. */ -static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED; -#endif +spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED; static int get_pid(unsigned long flags) { diff --git a/kernel/module.c b/kernel/module.c index ffd73ef85a15..ecba758feeb8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -120,7 +120,7 @@ sys_create_module(const char *name_user, size_t size) struct module *mod; lock_kernel(); - if (!suser()) { + if (!capable(CAP_SYS_MODULE)) { error = -EPERM; goto err0; } @@ -175,7 +175,7 @@ sys_init_module(const char *name_user, struct module *mod_user) struct module_ref *dep; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_MODULE)) goto err0; if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -366,7 +366,7 @@ sys_delete_module(const char *name_user) int something_changed; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_MODULE)) goto out; if (name_user) { diff --git a/kernel/printk.c b/kernel/printk.c index 48922d7795e4..9060da3ef282 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -130,7 +130,7 @@ asmlinkage int sys_syslog(int type, char * buf, int len) int error = -EPERM; lock_kernel(); - if ((type != 3) && !suser()) + if ((type != 3) && !capable(CAP_SYS_ADMIN)) goto out; error = 0; switch (type) { diff --git a/kernel/sched.c b/kernel/sched.c index f9246e78533b..af68649ef070 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1227,7 +1227,7 @@ asmlinkage int sys_nice(int increment) newprio = increment; if (increment < 0) { - if (!suser()) + if (!capable(CAP_SYS_NICE)) return -EPERM; newprio = -increment; increase = 1; @@ -1322,10 +1322,11 @@ static int setscheduler(pid_t pid, int policy, goto out_unlock; retval = -EPERM; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && !suser()) + if ((policy == SCHED_FIFO || policy == SCHED_RR) && + !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && - !suser()) + !capable(CAP_SYS_NICE)) goto out_unlock; retval = 0; diff --git a/kernel/signal.c b/kernel/signal.c index eccb06614d30..ca34cecbf6c5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -235,7 +235,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); && ((sig != SIGCONT) || (current->session != t->session)) && (current->euid ^ t->suid) && (current->euid ^ t->uid) && (current->uid ^ t->suid) && (current->uid ^ t->uid) - && !suser()) + && !capable(CAP_SYS_ADMIN)) goto out_nolock; /* The null signal is a permissions and process existance probe. diff --git a/kernel/sys.c b/kernel/sys.c index aadb3ab5fc1a..1de75c366b56 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -114,13 +114,13 @@ asmlinkage int sys_setpriority(int which, int who, int niceval) if (!proc_sel(p, which, who)) continue; if (p->uid != current->euid && - p->uid != current->uid && !suser()) { + p->uid != current->uid && !capable(CAP_SYS_NICE)) { error = EPERM; continue; } if (error == ESRCH) error = 0; - if (priority > p->priority && !suser()) + if (priority > p->priority && !capable(CAP_SYS_NICE)) error = EACCES; else p->priority = priority; @@ -172,7 +172,7 @@ asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg) char buffer[256]; /* We only trust the superuser with rebooting the system. */ - if (!suser()) + if (!capable(CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ @@ -273,7 +273,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || - suser()) + capable(CAP_SETGID)) current->gid = rgid; else return -EPERM; @@ -282,7 +282,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) if ((old_rgid == egid) || (current->egid == egid) || (current->sgid == egid) || - suser()) + capable(CAP_SETGID)) current->fsgid = current->egid = egid; else { current->gid = old_rgid; @@ -307,7 +307,7 @@ asmlinkage int sys_setgid(gid_t gid) { int old_egid = current->egid; - if (suser()) + if (capable(CAP_SETGID)) current->gid = current->egid = current->sgid = current->fsgid = gid; else if ((gid == current->gid) || (gid == current->sgid)) current->egid = current->fsgid = gid; @@ -319,6 +319,41 @@ asmlinkage int sys_setgid(gid_t gid) return 0; } +/* + * cap_emulate_setxuid() fixes the effective / permitted capabilities of + * a process after a call to setuid, setreuid, or setresuid. + * + * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of + * {r,e,s}uid != 0, the permitted and effective capabilities are + * cleared. + * + * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective + * capabilities of the process are cleared. + * + * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective + * capabilities are set to the permitted capabilities. + * + * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should + * never happen. + * + * -astor + */ +extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, + int old_suid) +{ + if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && + (current->uid != 0 && current->euid != 0 && current->suid != 0)) { + cap_clear(current->cap_permitted); + cap_clear(current->cap_effective); + } + if (old_euid == 0 && current->euid != 0) { + cap_clear(current->cap_effective); + } + if (old_euid != 0 && current->euid == 0) { + current->cap_effective = current->cap_permitted; + } +} + /* * Unprivileged users may change the real uid to the effective uid * or vice versa. (BSD-style) @@ -336,14 +371,15 @@ asmlinkage int sys_setgid(gid_t gid) */ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) { - int old_ruid, old_euid, new_ruid; + int old_ruid, old_euid, old_suid, new_ruid; new_ruid = old_ruid = current->uid; old_euid = current->euid; + old_suid = current->suid; if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || (current->euid==ruid) || - suser()) + capable(CAP_SETUID)) new_ruid = ruid; else return -EPERM; @@ -352,7 +388,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) if ((old_ruid == euid) || (current->euid == euid) || (current->suid == euid) || - suser()) + capable(CAP_SETUID)) current->fsuid = current->euid = euid; else return -EPERM; @@ -375,9 +411,16 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) if(new_ruid) charge_uid(current, 1); } + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + return 0; } + + /* * setuid() is implemented like SysV w/ SAVED_IDS * @@ -392,10 +435,11 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) asmlinkage int sys_setuid(uid_t uid) { int old_euid = current->euid; - int old_ruid, new_ruid; + int old_ruid, old_suid, new_ruid; old_ruid = new_ruid = current->uid; - if (suser()) + old_suid = current->suid; + if (capable(CAP_SETUID)) new_ruid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; @@ -412,6 +456,11 @@ asmlinkage int sys_setuid(uid_t uid) if(new_ruid) charge_uid(current, 1); } + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + return 0; } @@ -422,6 +471,9 @@ asmlinkage int sys_setuid(uid_t uid) */ asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + int old_ruid = current->uid; + int old_euid = current->euid; + int old_suid = current->suid; if (current->uid != 0 && current->euid != 0 && current->suid != 0) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) @@ -448,6 +500,11 @@ asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) } if (suid != (uid_t) -1) current->suid = suid; + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + return 0; } @@ -515,11 +572,31 @@ asmlinkage int sys_setfsuid(uid_t uid) old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || - uid == current->suid || uid == current->fsuid || suser()) + uid == current->suid || uid == current->fsuid || + capable(CAP_SETUID)) current->fsuid = uid; if (current->fsuid != old_fsuid) current->dumpable = 0; + /* We emulate fsuid by essentially doing a scaled-down version + * of what we did in setresuid and friends. However, we only + * operate on the fs-specific bits of the process' effective + * capabilities + * + * FIXME - is fsuser used for all CAP_FS_MASK capabilities? + * if not, we might be a bit too harsh here. + */ + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + if (old_fsuid == 0 && current->fsuid != 0) { + current->cap_effective.cap &= ~CAP_FS_MASK; + } + if (old_fsuid != 0 && current->fsuid == 0) { + current->cap_effective.cap |= + (current->cap_permitted.cap & CAP_FS_MASK); + } + } + return old_fsuid; } @@ -532,7 +609,8 @@ asmlinkage int sys_setfsgid(gid_t gid) old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || - gid == current->sgid || gid == current->fsgid || suser()) + gid == current->sgid || gid == current->fsgid || + capable(CAP_SETGID)) current->fsgid = gid; if (current->fsgid != old_fsgid) current->dumpable = 0; @@ -716,7 +794,7 @@ asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist) asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) { - if (!suser()) + if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; @@ -756,7 +834,7 @@ asmlinkage int sys_newuname(struct new_utsname * name) asmlinkage int sys_sethostname(char *name, int len) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -787,7 +865,7 @@ asmlinkage int sys_gethostname(char *name, int len) */ asmlinkage int sys_setdomainname(char *name, int len) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -820,7 +898,7 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && - !suser()) + !capable(CAP_SYS_RESOURCE)) return -EPERM; if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) @@ -916,3 +994,4 @@ asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, } return error; } + diff --git a/kernel/time.c b/kernel/time.c index e16a7a15007f..ff3a5d6843d1 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -87,7 +87,7 @@ asmlinkage int sys_stime(int * tptr) { int value; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EPERM; if (get_user(value, tptr)) return -EFAULT; @@ -156,7 +156,7 @@ int do_sys_settimeofday(struct timeval *tv, struct timezone *tz) { static int firsttime = 1; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EPERM; if (tz) { @@ -221,7 +221,7 @@ int do_adjtimex(struct timex *txc) long ltemp, mtemp, save_adjust; /* In order to modify anything, you gotta be super-user! */ - if (txc->modes && !suser()) + if (txc->modes && !capable(CAP_SYS_TIME)) return -EPERM; /* Now we validate the data before disabling interrupts */ diff --git a/mm/mlock.c b/mm/mlock.c index 5bffab93f0b6..3a322f8a540c 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -144,7 +144,7 @@ static int do_mlock(unsigned long start, size_t len, int on) struct vm_area_struct * vma, * next; int error; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; @@ -235,7 +235,7 @@ static int do_mlockall(int flags) unsigned int def_flags; struct vm_area_struct * vma; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; def_flags = 0; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d8b78d73afbd..339e11470463 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -98,9 +98,7 @@ static inline void remove_mem_queue(struct page * entry) * * Hint: -mask = 1+~mask */ -#ifdef __SMP__ -static spinlock_t page_alloc_lock; -#endif +static spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED; /* * This routine is used by the kernel swap deamon to determine diff --git a/mm/swapfile.c b/mm/swapfile.c index f9cd0d47e852..1a27f266a67c 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -356,7 +356,7 @@ asmlinkage int sys_swapoff(const char * specialfile) int err = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; dentry = namei(specialfile); @@ -491,7 +491,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) static int least_priority = 0; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; memset(&filp, 0, sizeof(filp)); p = swap_info; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index c56adc148b2c..b85835f475ae 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -719,7 +719,7 @@ int atif_ioctl(int cmd, void *arg) switch(cmd) { case SIOCSIFADDR: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return (-EPERM); if(sa->sat_family != AF_APPLETALK) return (-EINVAL); @@ -830,7 +830,7 @@ int atif_ioctl(int cmd, void *arg) case SIOCATALKDIFADDR: case SIOCDIFADDR: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return (-EPERM); if(sa->sat_family != AF_APPLETALK) return (-EINVAL); @@ -1809,7 +1809,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) */ case SIOCADDRT: case SIOCDELRT: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EPERM; return (atrtr_ioctl(cmd,(void *)arg)); diff --git a/net/core/dev.c b/net/core/dev.c index 1bb5dede15e2..69315d9483cf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -321,7 +321,7 @@ struct device *dev_alloc(const char *name, int *err) void dev_load(const char *name) { - if(!dev_get(name) && suser()) + if(!dev_get(name) && capable(CAP_SYS_MODULE)) request_module(name); } @@ -1591,7 +1591,7 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCDELMULTI: case SIOCSIFHWBROADCAST: case SIOCSIFTXQLEN: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); rtnl_lock(); diff --git a/net/core/scm.c b/net/core/scm.c index ac4aefda03eb..dd19cf5e0a96 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -45,19 +45,16 @@ static __inline__ int scm_check_creds(struct ucred *creds) { - /* N.B. The test for suser should follow the credential check */ - if (suser()) + if ((creds->pid == current->pid || capable(CAP_SYS_ADMIN)) && + ((creds->uid == current->uid || creds->uid == current->euid || + creds->uid == current->suid) || capable(CAP_SETUID)) && + ((creds->gid == current->gid || creds->gid == current->egid || + creds->gid == current->sgid) || capable(CAP_SETGID))) { return 0; - if (creds->pid != current->pid || - (creds->uid != current->uid && creds->uid != current->euid && - creds->uid != current->suid) || - (creds->gid != current->gid && creds->gid != current->egid && - creds->gid != current->sgid)) - return -EPERM; - return 0; + } + return -EPERM; } - static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) { int *fdp = (int*)CMSG_DATA(cmsg); diff --git a/net/core/sock.c b/net/core/sock.c index 30e5d3e77d09..428b4052c315 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -185,7 +185,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, switch(optname) { case SO_DEBUG: - if(val && !suser()) + if(val && !capable(CAP_NET_ADMIN)) { ret = -EACCES; } @@ -924,7 +924,7 @@ int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) */ if (current->pgrp != -arg && current->pid != arg && - !suser()) return(-EPERM); + !capable(CAP_NET_ADMIN)) return(-EPERM); sk->proc = arg; return(0); case F_GETOWN: diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index bba2bb96555d..d711075194bc 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -374,7 +374,7 @@ static int inet_create(struct socket *sock, int protocol) sock->ops = &inet_dgram_ops; break; case SOCK_RAW: - if (!suser()) + if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -521,7 +521,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) #endif if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); @@ -529,7 +529,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !suser()) + if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) #endif return -EADDRNOTAVAIL; /* Source address MUST be ours! */ } @@ -868,7 +868,8 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) err = get_user(pid, (int *) arg); if (err) return err; - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 425885cc2d61..63760de8033f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -435,7 +435,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) break; case SIOCSIFFLAGS: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EACCES; rtnl_lock(); exclusive = 1; @@ -444,7 +444,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) case SIOCSIFBRDADDR: /* Set the broadcast address */ case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFNETMASK: /* Set the netmask for the interface */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EACCES; if (sin->sin_family != AF_INET) return -EINVAL; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6350a6366006..24f3052fef85 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -253,7 +253,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) switch (cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&r, arg, sizeof(struct rtentry))) return -EFAULT; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index f60c206a0ad7..c2598eb96bc4 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -311,7 +311,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt /* Reject setting of unused bits */ if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK)) return -EINVAL; - if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && !suser()) + if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && + !capable(CAP_NET_ADMIN)) return -EPERM; if (sk->ip_tos != val) { sk->ip_tos=val; @@ -453,7 +454,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_FW_POLICY_OUT: case IP_FW_POLICY_FWD: case IP_FW_MASQ_TIMEOUTS: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; @@ -467,7 +468,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_FW_MASQ_ADD: case IP_FW_MASQ_DEL: case IP_FW_MASQ_FLUSH: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EPERM; if(optlen>sizeof(masq_ctl) || optlen<1) return -EINVAL; @@ -483,7 +484,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_ACCT_DELETE: case IP_ACCT_FLUSH: case IP_ACCT_ZERO: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 735d06d44640..f26df1442ab6 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -398,7 +398,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !suser()) + if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) #endif return -EADDRNOTAVAIL; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 80e40b49faaa..d9dfa8e76c84 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -646,7 +646,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) #ifdef CONFIG_IP_TRANSPARENT_PROXY if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_PROXY|MSG_NOSIGNAL)) return -EINVAL; - if ((msg->msg_flags&MSG_PROXY) && !suser() ) + if ((msg->msg_flags&MSG_PROXY) && !capable(CAP_NET_ADMIN)) return -EPERM; #else if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL)) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0241e0459072..5571c04c7bbe 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -894,7 +894,7 @@ int addrconf_add_ifaddr(void *arg) struct in6_ifreq ireq; int err; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) @@ -911,7 +911,7 @@ int addrconf_del_ifaddr(void *arg) struct in6_ifreq ireq; int err; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 902274ecb80e..c1b2e9d14b4e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -89,7 +89,7 @@ static int inet6_create(struct socket *sock, int protocol) prot=&udpv6_prot; sock->ops = &inet6_dgram_ops; } else if(sock->type == SOCK_RAW) { - if (!suser()) + if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -187,7 +187,7 @@ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) snum = ntohs(addr->sin6_port); if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); addr_type = ipv6_addr_type(&addr->sin6_addr); @@ -291,7 +291,8 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return err; /* see sock_no_fcntl */ - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a71c9c0e5833..3baa410076eb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1379,7 +1379,7 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg) switch(cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; err = copy_from_user(&rtmsg, arg, sizeof(struct in6_rtmsg)); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 858ea0e73f1f..f56b660c0df2 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -691,7 +691,7 @@ static int packet_create(struct socket *sock, int protocol) struct sock *sk; int err; - if (!suser()) + if (!capable(CAP_NET_RAW)) return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW #ifdef CONFIG_SOCK_PACKET @@ -1089,7 +1089,8 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg err = get_user(pid, (int *) arg); if (err) return err; - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 286a2aa6811c..494b9fa624a0 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1193,7 +1193,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: case SIOCRSCLRRT: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return rose_rt_ioctl(cmd, (void *)arg); case SIOCRSGCAUSE: { diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 30e2c2034bda..b00d0ab2ae4c 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -371,7 +371,7 @@ int wanrouter_ioctl(struct inode* inode, struct file* file, struct proc_dir_entry* dent; wan_device_t* wandev; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((cmd >> 8) != ROUTER_IOCTL) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 16396040913e..514f64e1b52f 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1096,7 +1096,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return x25_route_ioctl(cmd, (void *)arg); case SIOCX25GSUBSCRIP: -- 2.39.5