From cdcdf25aa015bc68d30e10f9158612170eb054e6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:35:59 -0500 Subject: [PATCH] Import 2.4.0-test3pre1 --- CREDITS | 2 +- Documentation/Changes | 8 +- Documentation/Configure.help | 47 ++ Makefile | 2 +- arch/alpha/Makefile | 8 +- arch/alpha/config.in | 4 +- arch/alpha/kernel/core_cia.c | 20 + arch/alpha/kernel/pci.c | 16 + arch/alpha/kernel/sys_sx164.c | 33 +- arch/alpha/{vmlinux.lds => vmlinux.lds.in} | 10 +- arch/arm/config.in | 5 +- arch/arm/kernel/armksyms.c | 4 +- arch/arm/kernel/arthur.c | 2 +- arch/arm/kernel/bios32.c | 1 - arch/arm/kernel/dma-footbridge.c | 1 - arch/arm/kernel/dma-rpc.c | 1 + arch/arm/kernel/dma.c | 2 +- arch/arm/kernel/ecard.c | 10 +- arch/arm/kernel/hw-footbridge.c | 145 +++--- arch/arm/kernel/hw-sa1100.c | 2 +- arch/arm/kernel/irq.c | 2 - arch/arm/kernel/isa.c | 1 - arch/arm/kernel/leds-footbridge.c | 2 +- arch/arm/kernel/leds-sa1100.c | 2 +- arch/arm/kernel/process.c | 10 +- arch/arm/kernel/ptrace.c | 571 +++++++++++---------- arch/arm/kernel/ptrace.h | 16 + arch/arm/kernel/semaphore.c | 1 - arch/arm/kernel/setup.c | 1 + arch/arm/kernel/signal.c | 23 +- arch/arm/kernel/time.c | 1 - arch/arm/kernel/traps.c | 126 +++-- arch/arm/mm/fault-common.c | 1 + arch/arm/mm/mm-armv.c | 28 +- arch/arm/mm/proc-arm2,3.S | 3 - arch/arm/mm/proc-arm6,7.S | 4 +- arch/arm/mm/proc-arm720.S | 4 +- arch/i386/kernel/pci-irq.c | 2 +- arch/sparc/kernel/sys_sparc.c | 4 +- arch/sparc/kernel/sys_sunos.c | 4 +- arch/sparc64/kernel/sys_sparc.c | 4 +- arch/sparc64/kernel/sys_sparc32.c | 5 +- arch/sparc64/kernel/sys_sunos32.c | 4 +- drivers/acorn/char/Makefile | 1 + drivers/acorn/char/defkeymap-acorn.c | 358 +++++++++++++ drivers/atm/fore200e.c | 2 - drivers/block/elevator.c | 2 + drivers/block/ll_rw_blk.c | 21 +- drivers/char/Makefile | 5 +- drivers/char/dz.c | 4 +- drivers/net/am79c961a.h | 4 +- drivers/net/sk_mca.c | 2 - drivers/pnp/isapnp.c | 2 + drivers/scsi/aic7xxx.c | 2 +- drivers/scsi/hosts.c | 2 +- drivers/scsi/qlogicfc.c | 70 +-- drivers/scsi/qlogicfc.h | 2 +- drivers/scsi/st.c | 46 +- drivers/sound/vidc.c | 1 + drivers/usb/serial/digi_acceleport.c | 155 ++---- drivers/usb/serial/usb-serial.h | 3 +- drivers/usb/serial/usbserial.c | 71 ++- drivers/usb/serial/visor.c | 6 +- drivers/video/sisfb.c | 6 +- fs/binfmt_elf.c | 6 +- fs/binfmt_em86.c | 2 + fs/binfmt_misc.c | 1 + fs/binfmt_script.c | 1 + fs/block_dev.c | 4 + fs/buffer.c | 11 +- fs/exec.c | 101 ++-- fs/ext2/super.c | 1 - fs/fcntl.c | 2 +- fs/file_table.c | 24 +- fs/hpfs/namei.c | 10 +- fs/ioctl.c | 2 +- fs/namei.c | 324 ++++++++---- fs/nfsd/export.c | 13 +- fs/nfsd/nfscache.c | 13 +- fs/nfsd/nfsctl.c | 1 - fs/nfsd/nfsfh.c | 16 +- fs/nfsd/nfsproc.c | 4 +- fs/nfsd/nfssvc.c | 12 - fs/nfsd/vfs.c | 136 ++--- fs/pipe.c | 2 + fs/proc/base.c | 1 + fs/qnx4/inode.c | 1 - fs/super.c | 216 ++++---- fs/sysv/inode.c | 1 - fs/udf/super.c | 1 - include/asm-alpha/pci.h | 5 +- include/asm-alpha/system.h | 7 +- include/asm-arm/arch-arc/ide.h | 8 +- include/asm-arm/arch-cl7500/ide.h | 5 +- include/asm-arm/arch-ebsa285/ide.h | 5 +- include/asm-arm/arch-l7200/ide.h | 2 +- include/asm-arm/arch-nexuspci/ide.h | 5 +- include/asm-arm/arch-rpc/ide.h | 8 +- include/asm-arm/arch-sa1100/ide.h | 14 +- include/asm-arm/arch-sa1100/irq.h | 3 +- include/asm-arm/arch-shark/hardware.h | 2 +- include/asm-arm/arch-shark/ide.h | 8 +- include/asm-arm/atomic.h | 28 +- include/asm-arm/cpu-multi26.h | 2 - include/asm-arm/dma.h | 3 +- include/asm-arm/floppy.h | 23 +- include/asm-arm/io.h | 21 +- include/asm-arm/memory.h | 31 ++ include/asm-arm/proc-armo/system.h | 26 +- include/asm-arm/proc-armv/system.h | 26 +- include/asm-arm/ptrace.h | 4 + include/asm-arm/system.h | 19 +- include/linux/fs.h | 35 +- include/linux/mm.h | 1 + include/linux/mount.h | 1 - include/linux/nfsd/cache.h | 4 +- include/linux/nfsd/export.h | 12 - include/linux/nfsd/nfsd.h | 11 +- include/linux/nfsd/nfsfh.h | 33 +- include/linux/pci_ids.h | 8 +- include/linux/socket.h | 13 - include/linux/vmalloc.h | 11 +- ipc/shm.c | 2 +- kernel/exec_domain.c | 49 +- kernel/ksyms.c | 2 +- kernel/module.c | 5 +- kernel/sched.c | 4 +- kernel/sysctl.c | 4 +- mm/filemap.c | 7 +- mm/mmap.c | 29 +- mm/page_alloc.c | 2 + mm/swap_state.c | 4 +- mm/swapfile.c | 14 +- mm/vmalloc.c | 18 +- net/netsyms.c | 2 +- net/sunrpc/svcsock.c | 11 + net/unix/af_unix.c | 2 +- 137 files changed, 2013 insertions(+), 1339 deletions(-) rename arch/alpha/{vmlinux.lds => vmlinux.lds.in} (92%) create mode 100644 arch/arm/kernel/ptrace.h create mode 100644 drivers/acorn/char/defkeymap-acorn.c create mode 100644 include/asm-arm/memory.h diff --git a/CREDITS b/CREDITS index 53968d777203..5ca87fc5de3e 100644 --- a/CREDITS +++ b/CREDITS @@ -950,7 +950,7 @@ S: London SE16 1GD S: United Kingdom N: Kai Harrekilde-Petersen -E: khp@olicom.dk +E: kai.harrekilde@get2net.dk D: Original author of the ftape-HOWTO, i82078 fdc detection code. N: Bart Hartgers diff --git a/Documentation/Changes b/Documentation/Changes index 0b9e549fc6f7..525932df1ecb 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -41,7 +41,7 @@ Card) hardware, for example, you probably needn't concern yourself with pcmcia-cs. o Gnu C 2.7.2.3 # gcc --version -o binutils 2.9.1.0.7 # ld -v +o binutils 2.9.1.0.22 # ld -v o util-linux 2.10g # chsh -v o modutils 2.3.10 # insmod -V o e2fsprogs 1.18 # /sbin/tune2fs --version @@ -78,7 +78,7 @@ release of binutils. If you can, upgrade to the latest 2.9.5 binutils release. Older releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if -at all possible. The later releases of 2.9.1.0.x (anything where x >= 7) +at all possible. The later releases of 2.9.1.0.x (anything where x >= 22) can and do compile the kernel properly, but there are many benefits to upgrading to 2.9.5 if you're up to it. @@ -248,8 +248,8 @@ o ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.t 2.9.5 series ------------ -o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.gz - +o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.gz + System utilities **************** diff --git a/Documentation/Configure.help b/Documentation/Configure.help index bc937c738ce7..b988920bb9f3 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2126,6 +2126,20 @@ CONFIG_ALPHA_SRM If unsure, say N. +Legacy kernel start address +CONFIG_ALPHA_LEGACY_START_ADDRESS + The 2.4 kernel changed the kernel start address from 0x310000 + to 0x810000 to make room for the Wildfire's larger SRM console. + + If you're using aboot 0.7 or later, the bootloader will examine + the ELF headers to determine where to transfer control. Unfortunately, + most older bootloaders -- APB, or MILO -- hardcoded the kernel + start address rather than examining the ELF headers, and the result + is a hard lockup. + + Say Y if you have a broken bootloader. Say N if you do not, or + if you wish to run on Wildfire. + Non-standard serial port support CONFIG_SERIAL_NONSTANDARD Say Y here if you have any non-standard serial boards -- boards @@ -3250,6 +3264,14 @@ CONFIG_FB_VIRTUAL If unsure, say N. +CONFIG_FB_SA1100 + This is a framebuffer device for the SA-1100 LCD Controller. + See http://www.linux-fbdev.org/ for information on framebuffer + devices. + + If you plan to use the LCD display with your SA-1100 system, say + Y here. + Advanced low level driver options CONFIG_FBCON_ADVANCED The frame buffer console uses character drawing routines that are @@ -15440,6 +15462,20 @@ CONFIG_ARCH_PERSONAL_SERVER If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com +Include support for Assabet +CONFIG_SA1100_ASSABET + Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 + Microprocessor Development Board (also known as the Assabet). + +Include support for the Compaq iPAQ 3600 +CONFIG_SA1100_BITSY + Say Y here if you intend to run this kernel on the Compaq iPAQ 3600 + handheld computer. Information about this machine and the Linux + port to this machine can be found at: + + http://www.handhelds.org/Compaq/index.html#iPAQ_H3600 + http://www.compaq.com/products/handhelds/pocketpc/ + Math emulation CONFIG_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. @@ -15496,6 +15532,17 @@ CONFIG_DEBUG_INFO time and disk space needed for compilation of the kernel. If in doubt say N. +Kernel low-level debugging functions +CONFIG_DEBUG_LL + Say Y here to include definitions of printascii, printchar, printhex + in the kernel. This is helpful if you are debugging code that + executes before the console is initialized. + +Kernel low-level debugging messages via footbridge serial port +CONFIG_DEBUG_DC21285_PORT + Say Y here if you want the low-level print routines to direct their + output to the serial port in the DC21285 (Footbridge). + Split initialisation functions into discardable section CONFIG_TEXT_SECTIONS If you say Y here, kernel code that is only used during diff --git a/Makefile b/Makefile index 523de4e0f7e0..7fdcef74cbd8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test2 +EXTRAVERSION = -test3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index 36f4d4e6df9f..3daa2c73cdd8 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -10,7 +10,7 @@ NM := nm -B -LINKFLAGS = -static -T arch/alpha/vmlinux.lds #-N -relax +LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8 # Determine if we can use the BWX instructions with GAS. @@ -90,7 +90,7 @@ endif LIBS := $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +MAKEBOOT = $(MAKE) -C arch/alpha/boot rawboot: @$(MAKEBOOT) rawboot @@ -109,13 +109,15 @@ srmboot: @$(MAKEBOOT) srmboot archclean: - @$(MAKE) -C arch/$(ARCH)/kernel clean + @$(MAKE) -C arch/alpha/kernel clean @$(MAKEBOOT) clean + rm -f arch/alpha/vmlinux.lds archmrproper: archdep: @$(MAKEBOOT) dep + $(CPP) $(CPPFLAGS) -xc -P arch/alpha/vmlinux.lds.in -o arch/alpha/vmlinux.lds bootpfile: @$(MAKEBOOT) bootpfile diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 5f344e0f57ef..7441083b6d49 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -331,7 +331,6 @@ source drivers/usb/Config.in mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel FP software completion' CONFIG_MATHEMU else @@ -339,4 +338,7 @@ else fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ + +bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS + endmenu diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 88c88a4e61a3..348bd843f2d4 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -19,6 +19,7 @@ #include #include +#include #define __EXTERN_INLINE inline #include @@ -712,6 +713,25 @@ cia_init_arch(void) void __init pyxis_init_arch(void) { + /* On pyxis machines we can precisely calculate the + CPU clock frequency using pyxis real time counter. + It's especially useful for SX164 with broken RTC. + + Both CPU and chipset are driven by the single 16.666M + or 16.667M crystal oscillator. PYXIS_RT_COUNT clock is + 66.66 MHz. -ink */ + + unsigned int cc0, cc1; + unsigned long pyxis_cc; + + __asm__ __volatile__ ("rpcc %0" : "=r"(cc0)); + pyxis_cc = *(vulp)PYXIS_RT_COUNT; + do { } while(*(vulp)PYXIS_RT_COUNT - pyxis_cc < 4096); + __asm__ __volatile__ ("rpcc %0" : "=r"(cc1)); + cc1 -= cc0; + hwrpb->cycle_freq = ((cc1 >> 11) * 100000000UL) / 3; + hwrpb_update_checksum(hwrpb); + do_init_arch(1); } diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 7a916ad08b9b..2dc6f00ddce7 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -369,6 +369,22 @@ pcibios_enable_device(struct pci_dev *dev) return 0; } +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as certain firmware forgets to set it properly, as seen + * on SX164 and LX164 with SRM. + */ +void +pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat >= 16) return; + printk("PCI: Setting latency timer of device %s to 64\n", + dev->slot_name); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); +} + #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) static void __init diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c index b98e46028312..19abbb6c3bb3 100644 --- a/arch/alpha/kernel/sys_sx164.c +++ b/arch/alpha/kernel/sys_sx164.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "proto.h" #include "irq_impl.h" @@ -114,6 +115,36 @@ sx164_init_pci(void) SMC669_Init(0); } +static void __init +sx164_init_arch(void) +{ + /* + * OSF palcode v1.23 forgets to enable PCA56 Motion Video + * Instructions. Let's enable it. + * We have to check palcode revision because CSERVE interface + * is subject to change without notice. For example, it + * has been changed completely since v1.16 (found in MILO + * distribution). -ink + */ + struct percpu_struct *cpu = (struct percpu_struct*) + ((char*)hwrpb + hwrpb->processor_offset); + + if (alpha_using_srm && (cpu->pal_revision & 0xffff) == 0x117) { + __asm__ __volatile__( + "lda $16,8($31)\n" + "call_pal 9\n" /* Allow PALRES insns in kernel mode */ + ".long 0x64000118\n\n" /* hw_mfpr $0,icsr */ + "ldah $16,(1<<(19-16))($31)\n" + "or $0,$16,$0\n" /* set MVE bit */ + ".long 0x74000118\n" /* hw_mtpr $0,icsr */ + "lda $16,9($31)\n" + "call_pal 9" /* Disable PALRES insns */ + : : : "$0", "$16"); + printk("PCA56 MVI set enabled\n"); + } + + pyxis_init_arch(); +} /* * The System Vector @@ -133,7 +164,7 @@ struct alpha_machine_vector sx164_mv __initmv = { nr_irqs: 48, device_interrupt: pyxis_device_interrupt, - init_arch: pyxis_init_arch, + init_arch: sx164_init_arch, init_irq: sx164_init_irq, init_rtc: common_init_rtc, init_pci: sx164_init_pci, diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds.in similarity index 92% rename from arch/alpha/vmlinux.lds rename to arch/alpha/vmlinux.lds.in index f64a926b6149..a153e5bd1ee1 100644 --- a/arch/alpha/vmlinux.lds +++ b/arch/alpha/vmlinux.lds.in @@ -1,10 +1,18 @@ +#include + OUTPUT_FORMAT("elf64-alpha") ENTRY(__start) +PHDRS { kernel PT_LOAD ; } SECTIONS { +#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS + . = 0xfffffc0000310000; +#else . = 0xfffffc0000810000; +#endif + _text = .; - .text : { *(.text) } + .text : { *(.text) } :kernel _etext = .; /* Exception table */ diff --git a/arch/arm/config.in b/arch/arm/config.in index ff683b30bfa3..15fba34032df 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -12,6 +12,7 @@ define_bool CONFIG_UID16 y mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE endmenu @@ -45,8 +46,8 @@ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET fi - bool ' Include support for Bitsy' CONFIG_SA1100_BITSY bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS + bool ' Include support for Compaq iPAQ 3600 (Bitsy)' CONFIG_SA1100_BITSY # bool ' Include support for Empeg' CONFIG_SA1100_EMPEG # bool ' Include support for Itsy' CONFIG_SA1100_ITSY bool ' Include support for LART' CONFIG_SA1100_LART @@ -342,7 +343,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL if [ "$CONFIG_DEBUG_LL" = "y" ]; then if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT + bool 'Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT fi fi fi diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index ffd0f1b5ef86..5ac0743be065 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -31,6 +31,8 @@ extern void outswb(unsigned int port, const void *to, int len); extern unsigned int local_bh_count[NR_CPUS]; extern unsigned int local_irq_count[NR_CPUS]; +extern void __bad_xchg(volatile void *ptr, int size); + /* * syscalls */ @@ -90,7 +92,6 @@ EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(udelay); -EXPORT_SYMBOL(xchg_str); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); #ifdef CONFIG_CPU_32 @@ -103,6 +104,7 @@ EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); EXPORT_SYMBOL(mem_fclk_21285); EXPORT_SYMBOL(__bug); +EXPORT_SYMBOL(__bad_xchg); EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); diff --git a/arch/arm/kernel/arthur.c b/arch/arm/kernel/arthur.c index 8a8a5510d591..0547302f8501 100644 --- a/arch/arm/kernel/arthur.c +++ b/arch/arm/kernel/arthur.c @@ -3,8 +3,8 @@ * Copyright (C) 1998-1999 Philip Blundell */ -#include #include +#include #include #include #include diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 2fbda24be571..a077f13b9972 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/kernel/dma-footbridge.c b/arch/arm/kernel/dma-footbridge.c index 65875831cdae..1d2ef26c4bdc 100644 --- a/arch/arm/kernel/dma-footbridge.c +++ b/arch/arm/kernel/dma-footbridge.c @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c index e1b54233b977..f4bc97f1d1a7 100644 --- a/arch/arm/kernel/dma-rpc.c +++ b/arch/arm/kernel/dma-rpc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 7d1a11cd599a..ff8322d34cab 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -14,9 +14,9 @@ * * Moved DMA resource allocation here... */ +#include #include #include -#include #include #include #include diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 61eb422b21b9..b4d38e00fea8 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -33,9 +33,7 @@ #include #include #include -#include #include -#include #include #include @@ -913,7 +911,6 @@ ecard_probe(int slot, card_type_t type) ecard_t **ecp; ecard_t *ec; struct ex_ecid cid; - char buffer[200]; int i, rc = -ENOMEM; ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); @@ -994,12 +991,9 @@ ecard_probe(int slot, card_type_t type) nodev: if (rc && ec) kfree(ec); - else { + else slot_to_expcard[slot] = ec; - ecard_prints(buffer, ec); - printk("%s", buffer); - } return rc; } @@ -1075,7 +1069,7 @@ void __init ecard_init(void) init_waitqueue_head(&ecard_done); #endif - printk("Probing expansion cards: (does not imply support)\n"); + printk("Probing expansion cards\n"); for (slot = 0; slot < 8; slot ++) { if (ecard_probe(slot, ECARD_EASI) == -ENODEV) diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c index 08aac078ea84..b56b944e7a95 100644 --- a/arch/arm/kernel/hw-footbridge.c +++ b/arch/arm/kernel/hw-footbridge.c @@ -8,19 +8,12 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include #include #include @@ -28,6 +21,13 @@ #define GP1_IO_BASE 0x338 #define GP2_IO_BASE 0x33a + +#ifdef CONFIG_LEDS +#define DEFAULT_LEDS 0 +#else +#define DEFAULT_LEDS GPIO_GREEN_LED +#endif + /* * Netwinder stuff */ @@ -396,9 +396,9 @@ static unsigned char rwa_unlock[] __initdata = 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; #ifndef DEBUG -#define dprintk if (0) printk +#define dprintk(x...) #else -#define dprintk printk +#define dprintk(x...) printk(x) #endif #define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) @@ -602,74 +602,13 @@ EXPORT_SYMBOL(gpio_modify_op); EXPORT_SYMBOL(gpio_modify_io); EXPORT_SYMBOL(cpld_modify); -#endif - -#ifdef CONFIG_LEDS -#define DEFAULT_LEDS 0 -#else -#define DEFAULT_LEDS GPIO_GREEN_LED -#endif - -/* - * CATS stuff - */ -#ifdef CONFIG_ARCH_CATS - -#define CONFIG_PORT 0x370 -#define INDEX_PORT (CONFIG_PORT) -#define DATA_PORT (CONFIG_PORT + 1) - -static void __init cats_hw_init(void) -{ - /* Set Aladdin to CONFIGURE mode */ - outb(0x51, CONFIG_PORT); - outb(0x23, CONFIG_PORT); - - /* Select logical device 3 */ - outb(0x07, INDEX_PORT); - outb(0x03, DATA_PORT); - - /* Set parallel port to DMA channel 3, ECP+EPP1.9, - enable EPP timeout */ - outb(0x74, INDEX_PORT); - outb(0x03, DATA_PORT); - - outb(0xf0, INDEX_PORT); - outb(0x0f, DATA_PORT); - - outb(0xf1, INDEX_PORT); - outb(0x07, DATA_PORT); - - /* Select logical device 4 */ - outb(0x07, INDEX_PORT); - outb(0x04, DATA_PORT); - - /* UART1 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Select logical device 5 */ - outb(0x07, INDEX_PORT); - outb(0x05, DATA_PORT); - - /* UART2 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Set Aladdin to RUN mode */ - outb(0xbb, CONFIG_PORT); -} - -#endif - /* * Initialise any other hardware after we've got the PCI bus * initialised. We may need the PCI bus to talk to this other * hardware. */ -static int __init hw_init(void) +static int __init nw_hw_init(void) { -#ifdef CONFIG_ARCH_NETWINDER /* * this ought to have a better home... * Since this calls the above routines, which are @@ -688,12 +627,66 @@ static int __init hw_init(void) gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); spin_unlock_irqrestore(&gpio_lock, flags); } + return 0; +} + +__initcall(nw_hw_init); #endif + +/* + * CATS stuff + */ #ifdef CONFIG_ARCH_CATS - if (machine_is_cats()) - cats_hw_init(); -#endif + +#define CONFIG_PORT 0x370 +#define INDEX_PORT (CONFIG_PORT) +#define DATA_PORT (CONFIG_PORT + 1) + +static int __init cats_hw_init(void) +{ + if (machine_is_cats()) { + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CONFIG_PORT); + outb(0x23, CONFIG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CONFIG_PORT); + } + return 0; } -__initcall(hw_init); +__initcall(cats_hw_init); +#endif + diff --git a/arch/arm/kernel/hw-sa1100.c b/arch/arm/kernel/hw-sa1100.c index 539bb721baae..862c3a2c4c60 100644 --- a/arch/arm/kernel/hw-sa1100.c +++ b/arch/arm/kernel/hw-sa1100.c @@ -10,9 +10,9 @@ * */ #include +#include #include #include -#include #include #include diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 7a761b7c6b7c..40a47c45fbdf 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -17,7 +17,6 @@ */ #include #include -#include #include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c index a5424f8b61b8..17696acb0381 100644 --- a/arch/arm/kernel/isa.c +++ b/arch/arm/kernel/isa.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c index 4fa2237ebc61..b309c2ea329e 100644 --- a/arch/arm/kernel/leds-footbridge.c +++ b/arch/arm/kernel/leds-footbridge.c @@ -18,8 +18,8 @@ * 02-05-1999 RMK Various cleanups */ #include -#include #include +#include #include #include diff --git a/arch/arm/kernel/leds-sa1100.c b/arch/arm/kernel/leds-sa1100.c index ef6918d7cbe9..f2f0325c3fa3 100644 --- a/arch/arm/kernel/leds-sa1100.c +++ b/arch/arm/kernel/leds-sa1100.c @@ -29,8 +29,8 @@ * */ #include -#include #include +#include #include #include diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 40b3b9e7244f..cab969c5c79e 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -7,28 +7,22 @@ #include -#include +#include #include #include #include -#include -#include #include #include #include #include -#include #include -#include -#include -#include #include #include #include -#include #include #include +#include /* * Values for cpu_do_idle() diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 1684c5f5f925..e45e03fcbe68 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -16,6 +15,10 @@ #include #include +#include "ptrace.h" + +#define REG_PC 15 +#define REG_PSR 16 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -26,6 +29,18 @@ */ #define BREAKINST 0xef9f0001 +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + */ +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task + 8192 - sizeof(struct pt_regs)); +} + /* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the THREAD. @@ -34,11 +49,7 @@ */ static inline long get_stack_long(struct task_struct *task, int offset) { - struct pt_regs *regs; - - regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - - return regs->uregs[offset]; + return get_user_regs(task)->uregs[offset]; } /* @@ -47,20 +58,16 @@ static inline long get_stack_long(struct task_struct *task, int offset) * this routine assumes that all the privileged stacks are in our * data space. */ -static inline long put_stack_long(struct task_struct *task, int offset, - unsigned long data) +static inline int +put_stack_long(struct task_struct *task, int offset, long data) { - struct pt_regs *regs; - - regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - - regs->uregs[offset] = data; + get_user_regs(task)->uregs[offset] = data; return 0; } -static int -read_long(struct task_struct *child, unsigned long addr, unsigned long *res) +static inline int +read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res) { int copied; @@ -69,8 +76,8 @@ read_long(struct task_struct *child, unsigned long addr, unsigned long *res) return copied != sizeof(*res) ? -EIO : 0; } -static int -write_long(struct task_struct *child, unsigned long addr, unsigned long val) +static inline int +write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val) { int copied; @@ -82,35 +89,33 @@ write_long(struct task_struct *child, unsigned long addr, unsigned long val) /* * Get value of register `rn' (in the instruction) */ -static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getrn(struct task_struct *child, unsigned long insn) { unsigned int reg = (insn >> 16) & 15; unsigned long val; + val = get_stack_long(child, reg); if (reg == 15) - val = pc_pointer (get_stack_long (child, reg)); - else - val = get_stack_long (child, reg); + val = pc_pointer(val); -printk ("r%02d=%08lX ", reg, val); return val; } /* * Get value of operand 2 (in an ALU instruction) */ -static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getaluop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; -printk ("op2="); if (insn & 1 << 25) { val = insn & 255; shift = (insn >> 8) & 15; type = 3; -printk ("(imm)"); } else { val = get_stack_long (child, insn & 15); @@ -120,9 +125,8 @@ printk ("(imm)"); shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("(r%02ld)", insn & 15); } -printk ("sh%dx%d", type, shift); + switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -133,24 +137,23 @@ printk ("sh%dx%d", type, shift); val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); return val; } /* * Get value of operand 2 (in a LDR instruction) */ -static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getldrop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; - val = get_stack_long (child, insn & 15); + val = get_stack_long(child, insn & 15); shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -161,7 +164,6 @@ printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); return val; } @@ -170,95 +172,72 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in { unsigned long alt = 0; -printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); - switch (insn & 0x0e100000) { + switch (insn & 0x0e000000) { case 0x00000000: - case 0x00100000: - case 0x02000000: - case 0x02100000: /* data processing */ - printk ("data "); - switch (insn & 0x01e0f000) { - case 0x0000f000: - alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn); - break; - case 0x0020f000: - alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn); - break; - case 0x0040f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn); - break; - case 0x0060f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn); - break; - case 0x0080f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn); - break; - case 0x00a0f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00c0f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00e0f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x0180f000: - alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn); - break; - case 0x01a0f000: - alt = ptrace_getaluop2(child, insn); - break; - case 0x01c0f000: - alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn); - break; - case 0x01e0f000: - alt = ~ptrace_getaluop2(child, insn); + case 0x02000000: { + /* + * data processing + */ + long aluop1, aluop2, ccbit; + + if ((insn & 0xf000) != 0xf000) break; + + aluop1 = ptrace_getrn(child, insn); + aluop2 = ptrace_getaluop2(child, insn); + ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0; + + switch (insn & 0x01e00000) { + case 0x00000000: alt = aluop1 & aluop2; break; + case 0x00200000: alt = aluop1 ^ aluop2; break; + case 0x00400000: alt = aluop1 - aluop2; break; + case 0x00600000: alt = aluop2 - aluop1; break; + case 0x00800000: alt = aluop1 + aluop2; break; + case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break; + case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break; + case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break; + case 0x01800000: alt = aluop1 | aluop2; break; + case 0x01a00000: alt = aluop2; break; + case 0x01c00000: alt = aluop1 & ~aluop2; break; + case 0x01e00000: alt = ~aluop2; break; } break; + } + + case 0x04000000: + case 0x06000000: + /* + * ldr + */ + if ((insn & 0x0010f000) == 0x0010f000) { + unsigned long base; - case 0x04100000: /* ldr */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldr "); - alt = ptrace_getrn(child, insn); + base = ptrace_getrn(child, insn); if (insn & 1 << 24) { - if (insn & 1 << 23) - alt += ptrace_getldrop2 (child, insn); + long aluop2; + + if (insn & 0x02000000) + aluop2 = ptrace_getldrop2(child, insn); else - alt -= ptrace_getldrop2 (child, insn); - } - if (read_long (child, alt, &alt) < 0) - alt = 0; /* not valid */ - else - alt = pc_pointer (alt); - } - break; + aluop2 = insn & 0xfff; - case 0x06100000: /* ldr imm */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldrimm "); - alt = ptrace_getrn(child, insn); - if (insn & 1 << 24) { if (insn & 1 << 23) - alt += insn & 0xfff; + base += aluop2; else - alt -= insn & 0xfff; + base -= aluop2; } - if (read_long (child, alt, &alt) < 0) - alt = 0; /* not valid */ - else - alt = pc_pointer (alt); + if (read_tsk_long(child, base, &alt) == 0) + alt = pc_pointer(alt); } break; - case 0x08100000: /* ldm */ - if (insn & (1 << 15)) { + case 0x08000000: + /* + * ldm + */ + if ((insn & 0x00108000) == 0x00108000) { unsigned long base; - int nr_regs; -printk ("ldm "); + unsigned int nr_regs; if (insn & (1 << 23)) { nr_regs = insn & 65535; @@ -278,23 +257,22 @@ printk ("ldm "); nr_regs = 0; } - base = ptrace_getrn (child, insn); + base = ptrace_getrn(child, insn); - if (read_long (child, base + nr_regs, &alt) < 0) - alt = 0; /* not valid */ - else + if (read_tsk_long(child, base + nr_regs, &alt) == 0) alt = pc_pointer (alt); break; } break; - case 0x0a000000: - case 0x0a100000: { /* bl or b */ + case 0x0a000000: { + /* + * bl or b + */ signed long displ; -printk ("b/bl "); /* It's a branch/branch link: instead of trying to * figure out whether the branch will be taken or not, - * we'll put a breakpoint at either location. This is + * we'll put a breakpoint at both locations. This is * simpler, more reliable, and probably not a whole lot * slower than the alternative approach of emulating the * branch. @@ -306,7 +284,6 @@ printk ("b/bl "); } break; } -printk ("=%08lX\n", alt); return alt; } @@ -318,9 +295,9 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long int res = -EINVAL; if (nr < 2) { - res = read_long(child, addr, &dbg->bp[nr].insn); + res = read_tsk_long(child, addr, &dbg->bp[nr].insn); if (res == 0) - res = write_long(child, addr, BREAKINST); + res = write_tsk_long(child, addr, BREAKINST); if (res == 0) { dbg->bp[nr].address = addr; @@ -332,257 +309,309 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long return res; } -int ptrace_set_bpt (struct task_struct *child) +int ptrace_set_bpt(struct task_struct *child) { - struct debug_info *dbg = &child->thread.debug; - unsigned long insn, pc, alt; + unsigned long insn, pc; int res; - pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); + pc = pc_pointer(get_stack_long(child, REG_PC)); - res = read_long(child, pc, &insn); - if (res >= 0) { - res = 0; + res = read_tsk_long(child, pc, &insn); + if (!res) { + struct debug_info *dbg = &child->thread.debug; + unsigned long alt; dbg->nsaved = 0; - res = add_breakpoint(child, dbg, pc + 4); + alt = get_branch_address(child, pc, insn); + if (alt) + res = add_breakpoint(child, dbg, alt); - if (res == 0) { - alt = get_branch_address(child, pc, insn); - if (alt) - res = add_breakpoint(child, dbg, alt); - } + if (!res && (!alt || predicate(insn) != PREDICATE_ALWAYS)) + res = add_breakpoint(child, dbg, pc + 4); } return res; } -/* Ensure no single-step breakpoint is pending. Returns non-zero +/* + * Ensure no single-step breakpoint is pending. Returns non-zero * value if child was being single-stepped. */ -int ptrace_cancel_bpt (struct task_struct *child) +void __ptrace_cancel_bpt(struct task_struct *child) { struct debug_info *dbg = &child->thread.debug; - unsigned long tmp; int i, nsaved = dbg->nsaved; dbg->nsaved = 0; if (nsaved > 2) { - printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } for (i = 0; i < nsaved; i++) { - read_long(child, dbg->bp[i].address, &tmp); + unsigned long tmp; + + read_tsk_long(child, dbg->bp[i].address, &tmp); if (tmp != BREAKINST) printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); - write_long(child, dbg->bp[i].address, dbg->bp[i].insn); + write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); } - - return nsaved != 0; } -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +static int do_ptrace(int request, struct task_struct *child, long addr, long data) { - struct task_struct *child; + unsigned long tmp; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - if (pid == 1) /* you may not mess with init */ - goto out; - ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) - goto out; - ret = -EPERM; - if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - send_sig(SIGSTOP, child, 1); - ret = 0; - goto out; - } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out; - } - if (child->p_pptr != current) - goto out; - switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - - ret = read_long(child, addr, &tmp); + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = read_tsk_long(child, addr, &tmp); if (!ret) ret = put_user(tmp, (unsigned long *) data); - goto out; - } - - case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */ - unsigned long tmp; + break; + /* + * read the word at location "addr" in the user registers. + */ + case PTRACE_PEEKUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; tmp = 0; /* Default return condition */ - if (addr < sizeof (struct pt_regs)) + if (addr < sizeof(struct pt_regs)) tmp = get_stack_long(child, (int)addr >> 2); ret = put_user(tmp, (unsigned long *)data); - goto out; - } + break; - case PTRACE_POKETEXT: /* write the word at location addr. */ + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = write_long(child, addr, data); - goto out; + ret = write_tsk_long(child, addr, data); + break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + /* + * write the word at location addr in the user registers. + */ + case PTRACE_POKEUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; if (addr < sizeof (struct pt_regs)) ret = put_stack_long(child, (int)addr >> 2, data); - goto out; + break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; + break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; - wake_up_process (child); /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + __ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - /* make the child exit. Best I can do is send it a sigkill. + /* + * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: - if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; - wake_up_process (child); + /* already dead */ + ret = 0; + if (child->state == TASK_ZOMBIE) + break; child->exit_code = SIGKILL; /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + __ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - case PTRACE_SINGLESTEP: /* execute single instruction. */ + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; + break; child->thread.debug.nsaved = -1; child->ptrace &= ~PT_TRACESYS; - wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ + wake_up_process(child); ret = 0; - goto out; - - case PTRACE_GETREGS: - { /* Get all gp regs from the child. */ - unsigned char *stack; + break; + + /* + * detach a process that was attached. + */ + case PTRACE_DETACH: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); + child->exit_code = data; + write_lock_irq(&tasklist_lock); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irq(&tasklist_lock); + /* make sure single-step breakpoint is gone. */ + __ptrace_cancel_bpt(child); + wake_up_process (child); + ret = 0; + break; + + /* + * Get all gp regs from the child. + */ + case PTRACE_GETREGS: { + struct pt_regs *regs = get_user_regs(child); ret = 0; - stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); - if (copy_to_user((void *)data, stack, + if (copy_to_user((void *)data, regs, sizeof(struct pt_regs))) ret = -EFAULT; - goto out; - }; + break; + } - case PTRACE_SETREGS: - { - /* Set all gp regs in the child. */ - unsigned char *stack; + /* + * Set all gp regs in the child. + */ + case PTRACE_SETREGS: { + struct pt_regs *regs = get_user_regs(child); ret = 0; - stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); - if (copy_from_user(stack, (void *)data, + if (copy_from_user(regs, (void *)data, sizeof(struct pt_regs))) ret = -EFAULT; - goto out; - }; + break; + } - case PTRACE_GETFPREGS: - /* Get the child FPU state. */ - ret = 0; - if (copy_to_user((void *)data, &child->thread.fpstate, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; + /* + * Get the child FPU state. + */ + case PTRACE_GETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp))) + break; + + /* we should check child->used_math here */ + ret = __copy_to_user((void *)data, &child->thread.fpstate, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; + /* + * Set the child FPU state. + */ case PTRACE_SETFPREGS: - /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->thread.fpstate, (void *)data, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; - - case PTRACE_DETACH: /* detach a process that was attached. */ ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); - wake_up_process (child); - child->exit_code = data; - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); - ret = 0; - goto out; + if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp))) + break; + + child->used_math = 1; + ret = __copy_from_user(&child->thread.fpstate, (void *)data, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; default: ret = -EIO; + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + if (child == current) + goto out_tsk; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + /* the same process cannot be attached many times */ + if (child->ptrace & PT_PTRACED) + goto out_tsk; + child->ptrace |= PT_PTRACED; + + write_lock_irq(&tasklist_lock); + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + write_unlock_irq(&tasklist_lock); + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED && request != PTRACE_KILL) + goto out_tsk; + if (child->p_pptr != current) + goto out_tsk; + + ret = do_ptrace(request, child, addr, data); + +out_tsk: + free_task_struct(child); out: unlock_kernel(); return ret; diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h new file mode 100644 index 000000000000..feae0acd8db0 --- /dev/null +++ b/arch/arm/kernel/ptrace.h @@ -0,0 +1,16 @@ +extern void __ptrace_cancel_bpt(struct task_struct *); +extern int ptrace_set_bpt(struct task_struct *); + +/* + * Clear a breakpoint, if one exists. + */ +static inline int ptrace_cancel_bpt(struct task_struct *tsk) +{ + int nsaved = tsk->thread.debug.nsaved; + + if (nsaved) + __ptrace_cancel_bpt(tsk); + + return nsaved; +} + diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c index 93a370f2dcfa..8118b6a68316 100644 --- a/arch/arm/kernel/semaphore.c +++ b/arch/arm/kernel/semaphore.c @@ -8,7 +8,6 @@ * Modified for ARM by Russell King */ #include -#include #include diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1f4295540837..c6010476a8f2 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -35,6 +35,7 @@ extern void paging_init(struct meminfo *); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); extern void disable_hlt(void); +extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 431dd96c1153..3e6cf6cb441a 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -10,18 +10,19 @@ #include #include #include -#include #include +#include #include #include -#include #include -#include +#include #include +#include #include #include -#include + +#include "ptrace.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -31,8 +32,6 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr, int options, unsigned long *ru); asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); -extern int ptrace_cancel_bpt (struct task_struct *); -extern int ptrace_set_bpt (struct task_struct *); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { @@ -234,7 +233,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) goto badframe; /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt (current)) + if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); return regs->ARM_r0; @@ -274,7 +273,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) goto badframe; /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt (current)) + if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); return regs->ARM_r0; @@ -500,7 +499,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (!oldset) oldset = ¤t->blocked; - single_stepping = ptrace_cancel_bpt (current); + single_stepping = ptrace_cancel_bpt(current); for (;;) { unsigned long signr; @@ -518,7 +517,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); - single_stepping |= ptrace_cancel_bpt (current); + single_stepping |= ptrace_cancel_bpt(current); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) @@ -617,7 +616,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); if (single_stepping) - ptrace_set_bpt (current); + ptrace_set_bpt(current); return 1; } @@ -629,6 +628,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) regs->ARM_pc -= 4; } if (single_stepping) - ptrace_set_bpt (current); + ptrace_set_bpt(current); return 0; } diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index bdb725551ded..d7f6640eb555 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -13,7 +13,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include -#include #include #include #include diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 1d692dd3503d..188f89722743 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -17,16 +17,18 @@ #include #include #include +#include #include -#include -#include -#include #include +#include #include +#include +#include + +#include "ptrace.h" extern void c_backtrace (unsigned long fp, int pmode); -extern int ptrace_cancel_bpt (struct task_struct *); char *processor_modes[]= { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , @@ -46,8 +48,6 @@ static inline void console_verbose(void) console_loglevel = 15; } -int kstack_depth_to_print = 200; - /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump @@ -199,37 +199,48 @@ void die_if_kernel(const char *str, struct pt_regs *regs, int err) die(str, regs, err); } -void bad_user_access_alignment(const void *ptr) -{ - printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, - __builtin_return_address(0)); - current->thread.error_code = 0; - current->thread.trap_no = 11; - force_sig(SIGBUS, current); -/* die_if_kernel("Oops - bad user access alignment", regs, mode);*/ -} - asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) { + unsigned long addr = instruction_pointer(regs); + siginfo_t info; + #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", - current->comm, current->pid, instruction_pointer(regs)); + current->comm, current->pid, addr); #endif + current->thread.error_code = 0; current->thread.trap_no = 6; - force_sig(SIGILL, current); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)addr; + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops - undefined instruction", regs, mode); } asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) { + siginfo_t info; + #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", current->comm, current->pid, instruction_pointer(regs)); #endif + current->thread.error_code = 0; current->thread.trap_no = 11; - force_sig(SIGBUS, current); + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + + force_sig_info(SIGBUS, &info, current); + die_if_kernel("Oops - address exception", regs, mode); } @@ -268,33 +279,39 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) while(1); } -/* - * 'math_state_restore()' saves the current math information in the - * old math state array, and gets the new ones from the current task. - * - * We no longer save/restore the math state on every context switch - * any more. We only do this now if it actually gets used. - */ -asmlinkage void math_state_restore (void) -{ - current->used_math = 1; -} - /* * Handle some more esoteric system calls */ -asmlinkage int arm_syscall (int no, struct pt_regs *regs) +asmlinkage int arm_syscall(int no, struct pt_regs *regs) { + siginfo_t info; + switch (no) { case 0: /* branch through 0 */ - force_sig(SIGSEGV, current); + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = NULL; + + force_sig_info(SIGSEGV, &info, current); + die_if_kernel("branch through zero", regs, 0); break; - case 1: /* SWI_BREAK_POINT */ - regs->ARM_pc -= 4; /* Decrement PC by one instruction */ - ptrace_cancel_bpt(current); - force_sig(SIGTRAP, current); + case 1: /* SWI BREAK_POINT */ + /* + * The PC is always left pointing at the next + * instruction. Fix this. + */ + regs->ARM_pc -= 4; + __ptrace_cancel_bpt(current); + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)instruction_pointer(regs); + + force_sig_info(SIGTRAP, &info, current); return regs->ARM_r0; case 2: /* sys_cacheflush */ @@ -350,29 +367,24 @@ asmlinkage void deferred(int n, struct pt_regs *regs) die_if_kernel("Oops", regs, n); } -asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr) -{ - printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc); -} - -asmlinkage void arm_invalidptr(const char *function, int size) +void __bad_xchg(volatile void *ptr, int size) { - printk("Invalid pointer size in %s (pc=%p) size %d\n", - function, __builtin_return_address(0), size); + printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", + __builtin_return_address(0), ptr, size); + BUG(); } /* - * A data abort trap was taken, but the instruction was not an instruction - * which should cause the trap to be taken. Try to abort it. Note that - * the while(1) is there because we cannot currently handle returning from - * this function. + * A data abort trap was taken, but we did not handle the instruction. + * Try to abort the user program, or panic if it was the kernel. */ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); + siginfo_t info; -#ifdef CONFIG_DEBUG_ERRORS +#ifdef CONFIG_DEBUG_USER dump_instr(addr, 1); { pgd_t *pgd; @@ -389,16 +401,22 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) printk ("\n"); } #endif - force_sig(SIGILL, current); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)addr; + + force_sig_info(SIGILL, &info, current); die_if_kernel("unknown data abort code", regs, instr); - while (1); } void __bug(const char *file, int line, void *data) { - printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line); + printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); if (data) - printk(KERN_CRIT"extra data = %p\n", data); + printk(KERN_CRIT" - extra data = %p", data); + printk("\n"); BUG(); } diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c index 3859377088b5..519f1965ac7b 100644 --- a/arch/arm/mm/fault-common.c +++ b/arch/arm/mm/fault-common.c @@ -187,6 +187,7 @@ static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) tsk->thread.error_code = mode; tsk->thread.trap_no = 14; si.si_signo = SIGSEGV; + si.si_errno = 0; si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR; si.si_addr = (void *)addr; force_sig_info(SIGSEGV, &si, tsk); diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 34bd513667d6..1edbc35fd938 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -410,9 +410,24 @@ void __init pagetable_init(struct meminfo *mi) flush_cache_all(); } -/* - * The mem_map array can get very big. Free the unused area of the memory map. - */ +static inline void free_memmap(unsigned long start, unsigned long end) +{ + unsigned long pg, pgend; + + start = __phys_to_virt(start); + end = __phys_to_virt(end); + + pg = PAGE_ALIGN((unsigned long)(mem_map + MAP_NR(start))); + pgend = ((unsigned long)(mem_map + MAP_NR(end))) & PAGE_MASK; + + start = __virt_to_phys(pg); + end = __virt_to_phys(pgend); + /* + * The mem_map is always stored in node 0 + */ + free_bootmem_node(0, start, end - start); +} + static inline void free_unused_memmap_node(int node, struct meminfo *mi) { unsigned long bank_start, prev_bank_end = 0; @@ -434,14 +449,17 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi) * between the current bank and the previous, free it. */ if (prev_bank_end && prev_bank_end != bank_start) - free_bootmem_node(node, prev_bank_end, - bank_start - prev_bank_end); + free_memmap(prev_bank_end, bank_start); prev_bank_end = PAGE_ALIGN(mi->bank[i].start + mi->bank[i].size); } } +/* + * The mem_map array can get very big. Free + * the unused area of the memory map. + */ void __init create_memmap_holes(struct meminfo *mi) { int node; diff --git a/arch/arm/mm/proc-arm2,3.S b/arch/arm/mm/proc-arm2,3.S index 36a9d8b28fca..6dd48c919477 100644 --- a/arch/arm/mm/proc-arm2,3.S +++ b/arch/arm/mm/proc-arm2,3.S @@ -286,7 +286,6 @@ SYMBOL_NAME(arm2_processor_functions): .word _arm2_proc_fin .word _arm2_set_pgd .word _arm2_xchg_1 - .word SYMBOL_NAME(abort) .word _arm2_xchg_4 cpu_arm2_info: @@ -300,7 +299,6 @@ SYMBOL_NAME(arm250_processor_functions): .word _arm2_proc_fin .word _arm2_set_pgd .word _arm3_xchg_1 - .word SYMBOL_NAME(abort) .word _arm3_xchg_4 cpu_arm250_info: @@ -314,7 +312,6 @@ SYMBOL_NAME(arm3_processor_functions): .word _arm3_proc_fin .word _arm3_set_pgd .word _arm3_xchg_1 - .word SYMBOL_NAME(abort) .word _arm3_xchg_4 cpu_arm3_info: diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S index 5d7605b851ba..b18d69d987d9 100644 --- a/arch/arm/mm/proc-arm6,7.S +++ b/arch/arm/mm/proc-arm6,7.S @@ -158,8 +158,8 @@ Ldata_unknown: @ Part of jumptable mov r0, r2 mov r1, r4 mov r2, r3 - b baddataabort - + bl baddataabort + b ret_from_sys_call Ldata_lateldrpreconst: tst r4, #1 << 21 @ check writeback bit diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index 738ff9a43407..d4919662520f 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -146,8 +146,8 @@ Ldata_unknown: @ Part of jumptable mov r0, r2 mov r1, r4 mov r2, r3 - b baddataabort - + bl baddataabort + b ret_from_sys_call Ldata_lateldrpreconst: tst r4, #1 << 21 @ check writeback bit diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c index 933d6c3c9894..b98bf47489d4 100644 --- a/arch/i386/kernel/pci-irq.c +++ b/arch/i386/kernel/pci-irq.c @@ -464,7 +464,7 @@ void __init pcibios_fixup_irqs(void) } } -void __init pcibios_penalize_isa_irq(int irq) +void pcibios_penalize_isa_irq(int irq) { /* * If any ISAPnP device reports an IRQ in its list of possible diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 05ed9d932be9..82d3027aa9f3 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -215,7 +215,6 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, goto out; } - down(¤t->mm->mmap_sem); lock_kernel(); retval = -EINVAL; len = PAGE_ALIGN(len); @@ -230,11 +229,12 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, goto out_putf; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up(¤t->mm->mmap_sem); out_putf: unlock_kernel(); - up(¤t->mm->mmap_sem); if (file) fput(file); out: diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 1c3dfe6e2c7b..f64563cab337 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -68,7 +68,6 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, struct file * file = NULL; unsigned long retval, ret_type; - down(¤t->mm->mmap_sem); lock_kernel(); if(flags & MAP_NORESERVE) { static int cnt; @@ -118,7 +117,9 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); + up(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < PAGE_OFFSET) ? 0 : retval); @@ -127,7 +128,6 @@ out_putf: fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return retval; } diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 9e51aadadc2a..2aff3033aa35 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -227,7 +227,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, len = PAGE_ALIGN(len); retval = -EINVAL; - down(¤t->mm->mmap_sem); lock_kernel(); if (current->thread.flags & SPARC_FLAG_32BIT) { @@ -241,11 +240,12 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out_putf; } + down(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); + up(¤t->mm->mmap_sem); out_putf: unlock_kernel(); - up(¤t->mm->mmap_sem); if (file) fput(file); out: diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 26c5faecdebd..e27892de30d7 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -3029,9 +3029,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0])); - lock_kernel(); file = open_exec(filename); - unlock_kernel(); retval = PTR_ERR(file); if (IS_ERR(file)) @@ -3043,10 +3041,12 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count32(argv)) < 0) { + allow_write_access(file); fput(file); return bprm.argc; } if ((bprm.envc = count32(envp)) < 0) { + allow_write_access(file); fput(file); return bprm.envc; } @@ -3075,6 +3075,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) out: /* Something went wrong, return the inode and free the argument pages*/ + allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index b13846fe9708..70adfe21a229 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -68,7 +68,6 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of struct file *file = NULL; unsigned long retval, ret_type; - down(¤t->mm->mmap_sem); lock_kernel(); if(flags & MAP_NORESERVE) { static int cnt; @@ -102,10 +101,12 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of flags &= ~_MAP_NEW; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, (unsigned long) off); + up(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval); out_putf: @@ -113,7 +114,6 @@ out_putf: fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return (u32) retval; } diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile index 316af0d4e71b..d4658724ad4b 100644 --- a/drivers/acorn/char/Makefile +++ b/drivers/acorn/char/Makefile @@ -33,6 +33,7 @@ obj-rpc := keyb_ps2.o obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o +obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o # Do the i2c and rtc last obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o diff --git a/drivers/acorn/char/defkeymap-acorn.c b/drivers/acorn/char/defkeymap-acorn.c new file mode 100644 index 000000000000..4974cd2b6b0f --- /dev/null +++ b/drivers/acorn/char/defkeymap-acorn.c @@ -0,0 +1,358 @@ +/* + * linux/arch/arm/drivers/char/defkeymap.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include + +/* Normal (maps 1:1 with no processing) */ +#define KTn 0xF0 +/* Function keys */ +#define KTf 0xF1 +/* Special (Performs special house-keeping funcs) */ +#define KTs 0xF2 +#define KIGNORE K(KTs, 0) /* Ignore */ +#define KENTER K(KTs, 1) /* Enter */ +#define KREGS K(KTs, 2) /* Regs */ +#define KMEM K(KTs, 3) /* Mem */ +#define KSTAT K(KTs, 4) /* State */ +#define KINTR K(KTs, 5) /* Intr */ +#define Ksl 6 /* Last console */ +#define KCAPSLK K(KTs, 7) /* Caps lock */ +#define KNUMLK K(KTs, 8) /* Num-lock */ +#define KSCRLLK K(KTs, 9) /* Scroll-lock */ +#define KSCRLFOR K(KTs,10) /* Scroll forward */ +#define KSCRLBAK K(KTs,11) /* Scroll back */ +#define KREBOOT K(KTs,12) /* Reboot */ +#define KCAPSON K(KTs,13) /* Caps on */ +#define KCOMPOSE K(KTs,14) /* Compose */ +#define KSAK K(KTs,15) /* SAK */ +#define CONS_DEC K(KTs,16) /* Dec console */ +#define CONS_INC K(KTs,17) /* Incr console */ +#define KFLOPPY K(KTs,18) /* Floppy */ +/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */ +#define KTp 0xF3 +#define KPAD_0 K(KTp, 0 ) +#define KPAD_1 K(KTp, 1 ) +#define KPAD_2 K(KTp, 2 ) +#define KPAD_3 K(KTp, 3 ) +#define KPAD_4 K(KTp, 4 ) +#define KPAD_5 K(KTp, 5 ) +#define KPAD_6 K(KTp, 6 ) +#define KPAD_7 K(KTp, 7 ) +#define KPAD_8 K(KTp, 8 ) +#define KPAD_9 K(KTp, 9 ) +#define KPAD_PL K(KTp,10 ) +#define KPAD_MI K(KTp,11 ) +#define KPAD_ML K(KTp,12 ) +#define KPAD_DV K(KTp,13 ) +#define KPAD_EN K(KTp,14 ) +#define KPAD_DT K(KTp,16 ) +#define KPAD_HS K(KTp,20 ) +/* Console switching */ +#define KCn 0xF5 +/* Cursor */ +#define KTc 0xF6 +#define Kcd 0 /* Cursor down */ +#define Kcl 1 /* Cursor left */ +#define Kcr 2 /* Cursor right */ +#define Kcu 3 /* Cursor up */ +/* Shift/alt modifiers etc */ +#define KMd 0xF7 +#define KSHIFT K(KMd, 0 ) +#define KALTGR K(KMd, 1 ) +#define KCTRL K(KMd, 2 ) +#define KALT K(KMd, 3 ) +/* Meta */ +#define KMt 0xF8 +#define KAs 0xF9 +#define KPADA_0 K(KAs, 0 ) +#define KPADA_1 K(KAs, 1 ) +#define KPADA_2 K(KAs, 2 ) +#define KPADA_3 K(KAs, 3 ) +#define KPADA_4 K(KAs, 4 ) +#define KPADA_5 K(KAs, 5 ) +#define KPADA_6 K(KAs, 6 ) +#define KPADA_7 K(KAs, 7 ) +#define KPADA_8 K(KAs, 8 ) +#define KPADA_9 K(KAs, 9 ) +#define KPADB_0 K(KAs,10 ) +#define KPADB_1 K(KAs,11 ) +#define KPADB_2 K(KAs,12 ) +#define KPADB_3 K(KAs,13 ) +#define KPADB_4 K(KAs,14 ) +#define KPADB_5 K(KAs,15 ) +#define KPADB_6 K(KAs,16 ) +#define KPADB_7 K(KAs,17 ) +#define KPADB_8 K(KAs,18 ) +#define KPADB_9 K(KAs,19 ) +/* Locking keys */ +#define KLk 0xFA +/* Letters */ +#define KTl 0xFB + +u_short plain_map[NR_KEYS]= +{ + K(KTn, 27),K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6), + K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSCRLLK ,KINTR , + K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'), + K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'q'), + K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'), + K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 , + KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'), + K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER , + KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'), + K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'), + KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '), + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short shift_map[NR_KEYS]= +{ + K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16), + K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE ,KMEM ,KINTR , + K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'), + K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ), + K(KTf,20 ),KSCRLBAK ,KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'Q'), + K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'), + K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR ,KPAD_7 , + KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'), + K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER , + KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'Z' ),K(KTl,'X'), + K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'), + KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '), + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short altgr_map[NR_KEYS]= +{ + KIGNORE ,K(KCn,12 ),K(KCn,13 ),K(KCn,14 ),K(KCn,15 ),K(KCn,16 ),K(KCn,17 ),K(KCn, 18), + K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22 ),K(KCn,23 ),KIGNORE ,KREGS ,KINTR , + KIGNORE ,KIGNORE ,K(KTn,'@'),KIGNORE ,K(KTn,'$'),KIGNORE ,KIGNORE ,K(KTn,'{'), + K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTl,'q'), + K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'), + K(KTl,'p'),KIGNORE ,K(KTn,'~'),KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADB_7 , + KPADB_8 ,KPADB_9 ,KPAD_MI ,KCTRL ,K(KAs,20 ),K(KTl,'s'),K(KAs,23 ),K(KAs,25 ), + K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE ,KIGNORE ,KENTER , + KPADB_4 ,KPADB_5 ,KPADB_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'), + K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE ,KIGNORE ,KIGNORE , + KSHIFT ,K(KTc,Kcu),KPADB_1 ,KPADB_2 ,KPADB_3 ,KCAPSLK ,KALT ,KIGNORE , + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short ctrl_map[NR_KEYS]= +{ + KIGNORE ,K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6), + K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSTAT ,KINTR , + KIGNORE ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3 ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6 ),K(KTn, 7 ), + K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31 ),KIGNORE ,KIGNORE ,K(KTn, 8 ),K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ), + K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ), + K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28 ),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 , + KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ), + K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER , + KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ), + K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KCOMPOSE ,K(KTn,127), + KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ), + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short shift_ctrl_map[NR_KEYS]= +{ + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KFLOPPY ,KINTR , + KIGNORE ,KIGNORE ,K(KTn, 0 ),KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,K(KTn,31 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ), + K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ), + K(KTn,16 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 , + KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ), + K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER , + KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ), + K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KIGNORE ,KIGNORE , + KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ), + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short alt_map[NR_KEYS]= +{ + K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ), + K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KSCRLLK ,KINTR , + K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'), + K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KMt, 9 ),K(KMt,'q'), + K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'), + K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADA_7 , + KPADA_8 ,KPADA_9 ,KPAD_MI ,KCTRL ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'), + K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ), + KPADA_4 ,KPADA_5 ,KPADA_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,'z' ),K(KMt,'x'), + K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE , + KSHIFT ,K(KTc,Kcu),KPADA_1 ,KPADA_2 ,KPADA_3 ,KCAPSLK ,KALT ,K(KMt,' '), + KALTGR ,KCTRL ,CONS_DEC ,K(KTc,Kcd ),CONS_INC ,KPADA_0 ,KPAD_DT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +u_short ctrl_alt_map[NR_KEYS]= +{ + KIGNORE ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ), + K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KIGNORE ,KINTR , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ), + K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KMt,17 ), + K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20 ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9 ),K(KMt,15 ), + K(KMt,16 ),KIGNORE ,KIGNORE ,KIGNORE ,KREBOOT ,K(KTf,23 ),K(KTf,25 ),KPAD_7 , + KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4 ),K(KMt, 6 ), + K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11 ),K(KMt,12 ),KIGNORE ,KIGNORE ,KENTER , + KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,26 ),K(KMt,24 ), + K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14 ),K(KMt,13 ),KIGNORE ,KIGNORE ,KIGNORE , + KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,KIGNORE , + KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KREBOOT ,KPAD_EN , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , + KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE , +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 82b2cc51049e..164ef4523a3d 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -56,9 +56,7 @@ #include #endif -#ifdef MODULE #include -#endif #include "fore200e.h" #include "suni.h" diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 2bf92251c850..1eee6d5458aa 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -138,6 +138,8 @@ void elevator_linus(struct request *req, elevator_t *elevator, struct list_head *entry = real_head; struct request *tmp; + req->elevator_sequence = orig_latency; + if (list_empty(real_head)) { list_add(&req->queue, real_head); return; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 2ed93b30079e..9646adbd0235 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -345,8 +345,6 @@ static inline struct request *get_request(request_queue_t *q, int rw) register struct request *rq = NULL; if (!list_empty(&q->request_freelist)) { - elevator_t *e = &q->elevator; - if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE)) return NULL; @@ -355,10 +353,6 @@ static inline struct request *get_request(request_queue_t *q, int rw) rq->rq_status = RQ_ACTIVE; rq->special = NULL; rq->q = q; - if (rq->cmd == READ) - rq->elevator_sequence = e->read_latency; - else - rq->elevator_sequence = e->write_latency; q->queue_requests++; } return rq; @@ -657,6 +651,13 @@ static inline void __make_request(request_queue_t * q, int rw, goto get_rq; } + /* + * skip first entry, for devices with active queue head + */ + head = &q->queue_head; + if (q->head_active && !q->plugged) + head = head->next; + el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments); switch (el_ret) { @@ -709,12 +710,12 @@ get_rq: req = __get_request_wait(q, rw); spin_lock_irq(&io_request_lock); + + head = &q->queue_head; + if (q->head_active && !q->plugged) + head = head->next; } - head = &q->queue_head; - if (q->head_active && !q->plugged) - head = head->next; - /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; diff --git a/drivers/char/Makefile b/drivers/char/Makefile index cf145729a743..30e649ac06dc 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -318,10 +318,7 @@ obj-$(L_DECODERS) += saa7110.o saa7111.o saa7185.o # set when a framegrabber implements i2c support obj-$(L_I2C) += i2c-old.o -ifeq ($(CONFIG_DZ),y) - L_OBJS += dz.o -endif - +obj-$(CONFIG_DZ) += dz.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o diff --git a/drivers/char/dz.c b/drivers/char/dz.c index b8165ef98935..d72bc629ecbd 100644 --- a/drivers/char/dz.c +++ b/drivers/char/dz.c @@ -1566,11 +1566,9 @@ static struct console dz_sercons = { NULL }; -long __init dz_serial_console_init(long kmem_start, long kmem_end) +void __init dz_serial_console_init(l) { register_console(&dz_sercons); - - return kmem_start; } #endif /* ifdef CONFIG_SERIAL_CONSOLE */ diff --git a/drivers/net/am79c961a.h b/drivers/net/am79c961a.h index 377c1b5d1361..b2c5493344c3 100644 --- a/drivers/net/am79c961a.h +++ b/drivers/net/am79c961a.h @@ -73,7 +73,8 @@ #define MODE_COLL 0x0010 #define MODE_DRETRY 0x0020 #define MODE_INTLOOP 0x0040 -#define MODE_PORT0 0x0080 +#define MODE_PORT_AUI 0x0000 +#define MODE_PORT_10BT 0x0080 #define MODE_DRXPA 0x2000 #define MODE_DRXBA 0x4000 #define MODE_PROMISC 0x8000 @@ -105,6 +106,7 @@ #define TST_LCAR 0x0800 #define TST_LCOL 0x1000 #define TST_UFLO 0x4000 +#define TST_BUFF 0x8000 struct dev_priv { struct enet_statistics stats; diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c index f28196a2fe19..1b8e48e0f165 100644 --- a/drivers/net/sk_mca.c +++ b/drivers/net/sk_mca.c @@ -95,10 +95,8 @@ History: #include #include -#ifdef MODULE #include #include -#endif #include #include diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c index 2115cdac9c43..4b2aacce6ea5 100644 --- a/drivers/pnp/isapnp.c +++ b/drivers/pnp/isapnp.c @@ -527,9 +527,11 @@ static void __init isapnp_add_irq_resource(struct pci_dev *dev, ptr->next = irq; else (*res)->irq = irq; +#ifdef CONFIG_PCI for (i=0; i<16; i++) if (irq->map & i) pcibios_penalize_isa_irq(i); +#endif } /* diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index d9f952ca6185..7cbbc3f1f4e6 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -9092,7 +9092,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1) p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; } } - p->sc = *sc; + memcpy(&p->sc, sc, sizeof(struct seeprom_config)); } p->discenable = 0; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 2496fce816c2..698849a4d9e6 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -668,7 +668,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #endif /* Put I2O last so that host specific controllers always win */ #ifdef CONFIG_I2O_SCSI - I2OSCSI + I2OSCSI, #endif /* "Removable host adapters" below this line (Parallel Port/USB/other) */ #ifdef CONFIG_SCSI_PPA diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 825c777825ac..6200afafc9af 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -72,12 +72,21 @@ typedef dma_addr_t dma64_addr_t; #define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir)) #define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir)) #define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir)) +#if BITS_PER_LONG > 32 +#define pci64_dma_hi32(a) ((u32) (0xffffffff & (a>>32))) +#define pci64_dma_lo32(a) ((u32) (0xffffffff & (a))) +#else #define pci64_dma_hi32(a) 0 #define pci64_dma_lo32(a) (a) +#endif /* BITS_PER_LONG */ #define pci64_dma_build(hi,lo) (lo) #define sg_dma64_address(s) sg_dma_address(s) #define sg_dma64_len(s) sg_dma_len(s) +#if BITS_PER_LONG > 32 +#define PCI64_DMA_BITS 64 +#else #define PCI64_DMA_BITS 32 +#endif /* BITS_PER_LONG */ #endif #include "qlogicfc.h" @@ -101,15 +110,12 @@ typedef dma_addr_t dma64_addr_t; #define ISP2x00_FABRIC 1 /* Macros used for debugging */ -/* -#define DEBUG_ISP2x00 1 -#define DEBUG_ISP2x00_INT 1 -#define DEBUG_ISP2x00_INTR 1 -#define DEBUG_ISP2x00_SETUP 1 - -#define DEBUG_ISP2x00_FABRIC 1 -*/ -/* #define TRACE_ISP 1 */ +#define DEBUG_ISP2x00 0 +#define DEBUG_ISP2x00_INT 0 +#define DEBUG_ISP2x00_INTR 0 +#define DEBUG_ISP2x00_SETUP 0 +#define DEBUG_ISP2x00_FABRIC 0 +#define TRACE_ISP 0 #define DEFAULT_LOOP_COUNT 1000000000 @@ -1233,7 +1239,7 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1))); if (!hostdata->handle_ptrs[i]) { - cmd->handle = i; + cmd->handle = cpu_to_le32(i); hostdata->handle_ptrs[i] = Cmnd; hostdata->handle_serials[i] = Cmnd->serial_number; } else { @@ -1358,6 +1364,13 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) break; } } + /* + * TEST_UNIT_READY commands from scsi_scan will fail due to "overlapped + * commands attempted" unless we setup at least a simple queue (midlayer + * will embelish this once it can do an INQUIRY command to the device) + */ + else + cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; @@ -1541,12 +1554,14 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr))); while (out_ptr != in_ptr) { + unsigned le_hand; sts = (struct Status_Entry *) &hostdata->res[out_ptr*QUEUE_ENTRY_LEN]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; TRACE("done", out_ptr, Cmnd); DEBUG_INTR(isp2x00_print_status_entry(sts)); - if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { + le_hand = le32_to_cpu(sts->handle); + if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[le_hand])) { Cmnd->result = isp2x00_return_status(Cmnd, sts); hostdata->queued--; @@ -1565,10 +1580,10 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) * we dont have to call done because the upper * level should already know its aborted. */ - if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number + if (hostdata->handle_serials[le_hand] != Cmnd->serial_number || le16_to_cpu(sts->completion_status) == CS_ABORTED){ - hostdata->handle_serials[sts->handle] = 0; - hostdata->handle_ptrs[sts->handle] = NULL; + hostdata->handle_serials[le_hand] = 0; + hostdata->handle_ptrs[le_hand] = NULL; outw(out_ptr, host->io_port + MBOX5); continue; } @@ -1589,7 +1604,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) continue; } - hostdata->handle_ptrs[sts->handle] = NULL; + hostdata->handle_ptrs[le_hand] = NULL; if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) @@ -1912,23 +1927,14 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host) } #endif -#ifdef __BIG_ENDIAN - { - u64 val; - memcpy(&val, &hostdata->control_block.node_name, sizeof(u64)); - hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8) - | ((val & 0x00ff00ff00ff00ffULL) << 8); - } -#else - hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0x00ff) << 48; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0x00ff) << 24; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; - hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; -#endif + hostdata->wwn = (u64) (cpu_to_le16(hostdata->control_block.node_name[0])) << 56; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[0]) & 0xff00) << 48; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0xff00) << 24; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0x00ff) << 48; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0x00ff) << 24; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0xff00) << 8; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8; + hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8; /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */ busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block), diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h index e00e8c64510a..10539d3db8fc 100644 --- a/drivers/scsi/qlogicfc.h +++ b/drivers/scsi/qlogicfc.h @@ -62,7 +62,7 @@ * determined for each queue request anew. */ -#if PCI64_DMA_BITS > 32 +#if BITS_PER_LONG > 32 #define DATASEGS_PER_COMMAND 2 #define DATASEGS_PER_CONT 5 #else diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index bdc3e8002f47..a605233c0cca 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,7 +12,7 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local + Last modified: Sat Jun 17 15:21:49 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -65,10 +65,10 @@ #include "constants.h" -static int buffer_kbs = 0; -static int write_threshold_kbs = 0; +static int buffer_kbs; +static int write_threshold_kbs; static int max_buffers = (-1); -static int max_sg_segs = 0; +static int max_sg_segs; MODULE_AUTHOR("Kai Makisara"); MODULE_DESCRIPTION("SCSI Tape Driver"); @@ -138,7 +138,7 @@ static int st_max_sg_segs = ST_MAX_SG; static Scsi_Tape **scsi_tapes = NULL; -static int modes_defined = FALSE; +static int modes_defined; static ST_buffer *new_tape_buffer(int, int); static int enlarge_buffer(ST_buffer *, int, int); @@ -870,7 +870,7 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) static int scsi_tape_flush(struct file *filp) { int result = 0, result2; - static unsigned char cmd[MAX_COMMAND_SIZE]; + unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; @@ -1027,7 +1027,7 @@ static ssize_t ssize_t retval = 0; int write_threshold; int doing_write = 0; - static unsigned char cmd[MAX_COMMAND_SIZE]; + unsigned char cmd[MAX_COMMAND_SIZE]; const char *b_point; Scsi_Request *SRpnt = NULL; Scsi_Tape *STp; @@ -1380,7 +1380,7 @@ static ssize_t static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt) { int transfer, blks, bytes; - static unsigned char cmd[MAX_COMMAND_SIZE]; + unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; ST_mode *STm; ST_partstat *STps; @@ -2945,24 +2945,34 @@ static int st_ioctl(struct inode *inode, struct file *file, if (mtc.mt_op == MTSETPART) { if (!STp->can_partitions || - mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) - return (-EINVAL); + mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) { + retval = (-EINVAL); + goto out; + } if (mtc.mt_count >= STp->nbr_partitions && - (STp->nbr_partitions = nbr_partitions(STp)) < 0) - return (-EIO); - if (mtc.mt_count >= STp->nbr_partitions) - return (-EINVAL); + (STp->nbr_partitions = nbr_partitions(STp)) < 0) { + retval = (-EIO); + goto out; + } + if (mtc.mt_count >= STp->nbr_partitions) { + retval = (-EINVAL); + goto out; + } STp->new_partition = mtc.mt_count; retval = 0; goto out; } if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) - return (-EINVAL); + if (!STp->can_partitions) { + retval = (-EINVAL); + goto out; + } if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 || - (i = partition_tape(STp, mtc.mt_count)) < 0) - return i; + (i = partition_tape(STp, mtc.mt_count)) < 0) { + retval = i; + goto out; + } for (i = 0; i < ST_NBR_PARTITIONS; i++) { STp->ps[i].rw = ST_IDLE; STp->ps[i].at_sm = 0; diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c index 6342e511a50b..01fb315ab37f 100644 --- a/drivers/sound/vidc.c +++ b/drivers/sound/vidc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "sound_config.h" diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index c3cce34c3668..dddf52c608e8 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -14,6 +14,18 @@ * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) * +* (6/22/2000) pberger and borchers +* -- Made cond_wait_... inline--apparently on SPARC the flags arg +* to spin_lock_irqsave cannot be passed to another function +* to call spin_unlock_irqrestore. Thanks to Pauline Middelink. +* -- In digi_set_modem_signals the inner nested spin locks use just +* spin_lock() rather than spin_lock_irqsave(). The old code +* mistakenly left interrupts off. Thanks to Pauline Middelink. +* -- copy_from_user (which can sleep) is no longer called while a +* spinlock is held. We copy to a local buffer before getting +* the spinlock--don't like the extra copy but the code is simpler. +* -- Printk and dbg are no longer called while a spin lock is held. +* * (6/4/2000) pberger and borchers * -- Replaced separate calls to spin_unlock_irqrestore and * interruptible_sleep_on_interruptible with a new function @@ -119,8 +131,10 @@ * - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to * recheck the condition they are sleeping on. This is defensive, * in case a wake up is lost. +* - Following Documentation/DocBook/kernel-locking.pdf no spin locks +* are held when calling copy_to/from_user or printk. * -* $Id: digi_acceleport.c,v 1.56 2000/06/07 22:47:30 root Exp root $ +* $Id: digi_acceleport.c,v 1.60 2000/06/23 17:43:17 root Exp root $ */ #include @@ -402,7 +416,7 @@ struct usb_serial_device_type digi_acceleport_device = { * wake ups. This is used to implement condition variables. */ -static long cond_wait_interruptible_timeout_irqrestore( +static inline long cond_wait_interruptible_timeout_irqrestore( wait_queue_head_t *q, long timeout, spinlock_t *lock, unsigned long flags ) { @@ -515,17 +529,17 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) { count -= len; buf += len; - } else { - dbg( - "digi_write_oob_command: usb_submit_urb failed, ret=%d", - ret ); - break; } } spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); + if( ret ) { + dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d", + ret ); + } + return( ret ); } @@ -569,8 +583,8 @@ count ); } /* len must be a multiple of 4 and small enough to */ - /* guarantee the write will send all data (or none), */ - /* so commands are not split */ + /* guarantee the write will send buffered data first, */ + /* so commands are in order with data and not split */ len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); if( len > 4 ) len &= ~3; @@ -588,35 +602,21 @@ count ); port->write_urb->transfer_buffer_length = len; } -#ifdef DEBUG_DATA - { - int i; - - printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=", - priv->dp_port_num, port->write_urb->transfer_buffer_length ); - for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { - printk( "%.2x ", - ((unsigned char *)port->write_urb->transfer_buffer)[i] ); - } - printk( "\n" ); - } -#endif - if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { priv->dp_buf_len = 0; count -= len; buf += len; - } else { - dbg( - "digi_write_inb_command: usb_submit_urb failed, ret=%d", - ret ); - break; } } spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + if( ret ) { + dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d", + ret ); + } + return( ret ); } @@ -647,10 +647,10 @@ dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", port_priv->dp_port_num, modem_signals ); spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); - spin_lock_irqsave( &port_priv->dp_port_lock, flags ); + spin_lock( &port_priv->dp_port_lock ); while( oob_port->write_urb->status == -EINPROGRESS ) { - spin_unlock_irqrestore( &port_priv->dp_port_lock, flags ); + spin_unlock( &port_priv->dp_port_lock ); cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); @@ -658,7 +658,7 @@ port_priv->dp_port_num, modem_signals ); return( -EINTR ); } spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); - spin_lock_irqsave( &port_priv->dp_port_lock, flags ); + spin_lock( &port_priv->dp_port_lock ); } data[0] = DIGI_CMD_SET_DTR_SIGNAL; @@ -679,14 +679,16 @@ port_priv->dp_port_num, modem_signals ); port_priv->dp_modem_signals = (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) | (modem_signals&(TIOCM_DTR|TIOCM_RTS)); - } else { - dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d", - ret ); } - spin_unlock_irqrestore( &port_priv->dp_port_lock, flags ); + spin_unlock( &port_priv->dp_port_lock ); spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); + if( ret ) { + dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d", + ret ); + } + return( ret ); } @@ -1046,12 +1048,19 @@ static int digi_write( struct usb_serial_port *port, int from_user, int ret,data_len,new_len; digi_private_t *priv = (digi_private_t *)(port->private); unsigned char *data = port->write_urb->transfer_buffer; + unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */ unsigned long flags = 0; dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d", priv->dp_port_num, count, from_user, in_interrupt() ); + /* copy user data (which can sleep) before getting spin lock */ + count = MIN( 64, MIN( count, port->bulk_out_size-2 ) ); + if( from_user && copy_from_user( user_buf, buf, count ) ) { + return( -EFAULT ); + } + /* be sure only one write proceeds at a time */ /* there are races on the port private buffer */ /* and races to check write_urb->status */ @@ -1096,40 +1105,19 @@ priv->dp_port_num, count, from_user, in_interrupt() ); data += priv->dp_buf_len; /* copy in new data */ - if( from_user ) { - if( copy_from_user( data, buf, new_len ) ) { - spin_unlock_irqrestore( &priv->dp_port_lock, flags ); - return( -EFAULT ); - } - } else { - memcpy( data, buf, new_len ); - } - -#ifdef DEBUG_DATA - { - int i; - - printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=", - priv->dp_port_num, port->write_urb->transfer_buffer_length ); - for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { - printk( "%.2x ", - ((unsigned char *)port->write_urb->transfer_buffer)[i] ); - } - printk( "\n" ); - } -#endif + memcpy( data, from_user ? user_buf : buf, new_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { ret = new_len; priv->dp_buf_len = 0; - } else { - dbg( "digi_write: usb_submit_urb failed, ret=%d", - ret ); } /* return length of new data written, or error */ -dbg( "digi_write: returning %d", ret ); spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + if( ret < 0 ) { + dbg( "digi_write: usb_submit_urb failed, ret=%d", ret ); + } +dbg( "digi_write: returning %d", ret ); return( ret ); } @@ -1175,24 +1163,8 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num ); memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf, priv->dp_buf_len ); -#ifdef DEBUG_DATA - { - int i; - - printk( KERN_DEBUG __FILE__ ": digi_write_bulk_callback: port=%d, length=%d, data=", - priv->dp_port_num, port->write_urb->transfer_buffer_length ); - for( i=0; iwrite_urb->transfer_buffer_length; ++i ) { - printk( "%.2x ", - ((unsigned char *)port->write_urb->transfer_buffer)[i] ); - } - printk( "\n" ); - } -#endif - if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { priv->dp_buf_len = 0; - } else { - dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d", ret ); } } @@ -1202,6 +1174,11 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num ); spin_unlock( &priv->dp_port_lock ); + if( ret ) { + dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d", + ret ); + } + /* also queue up a wakeup at scheduler time, in case we */ /* lost the race in write_chan(). */ priv->dp_tasks.routine = (void *)digi_wakeup_write_lock; @@ -1219,8 +1196,6 @@ static int digi_write_room( struct usb_serial_port *port ) unsigned long flags = 0; -dbg( "digi_write_room: TOP: port=%d", priv->dp_port_num ); - spin_lock_irqsave( &priv->dp_port_lock, flags ); if( port->write_urb->status == -EINPROGRESS ) @@ -1242,8 +1217,6 @@ static int digi_chars_in_buffer( struct usb_serial_port *port ) digi_private_t *priv = (digi_private_t *)(port->private); -dbg( "digi_chars_in_buffer: TOP: port=%d", priv->dp_port_num ); - if( port->write_urb->status == -EINPROGRESS ) { dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 ); /* return( port->bulk_out_size - 2 ); */ @@ -1455,13 +1428,14 @@ static int digi_startup_device( struct usb_serial *serial ) int i,ret = 0; - spin_lock( &startup_lock ); - /* be sure this happens exactly once */ + spin_lock( &startup_lock ); if( device_startup ) { spin_unlock( &startup_lock ); return( 0 ); } + device_startup = 1; + spin_unlock( &startup_lock ); /* start reading from each bulk in endpoint for the device */ for( i=0; idp_port_num ); goto resubmit; } -#ifdef DEBUG_DATA -if( urb->actual_length ) { - printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: port=%d, length=%d, data=", - priv->dp_port_num, urb->actual_length ); - for( i=0; iactual_length; ++i ) { - printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] ); - } - printk( "\n" ); -} -#endif - if( urb->actual_length != len + 2 ) err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", priv->dp_port_num, opcode, len, urb->actual_length, status ); diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index b8e2e1d7445f..430a8fa64781 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -51,6 +51,8 @@ struct usb_serial_port { wait_queue_head_t write_wait; + struct tq_struct tqueue; /* task queue for line discipline waking up */ + void * private; /* data private to the specific port */ }; @@ -178,6 +180,5 @@ static inline int port_paranoia_check (struct usb_serial_port *port, const char return 0; } - #endif /* ifdef __LINUX_USB_SERIAL_H */ diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index d60fd8e333fb..261d5ac006ad 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -14,6 +14,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (06/25/2000) gkh + * Changed generic_write_bulk_callback to not call wake_up_interruptible + * directly, but to have port_softint do it at a safer time. + * * (06/23/2000) gkh * Cleaned up debugging statements in a quest to find UHCI timeout bug. * @@ -222,6 +226,8 @@ #include #include #include +#include +#include #ifdef CONFIG_USB_SERIAL_DEBUG #define DEBUG @@ -803,36 +809,32 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns static int generic_write_room (struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - int room; + int room = 0; dbg(__FUNCTION__ " - port %d", port->number); - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) - room = 0; - else + if (serial->num_bulk_out) + if (port->write_urb->status != -EINPROGRESS) room = port->bulk_out_size; - dbg(__FUNCTION__ " returns %d", room); - return (room); - } - return (0); + dbg(__FUNCTION__ " - returns %d", room); + return (room); } static int generic_chars_in_buffer (struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + int chars = 0; dbg(__FUNCTION__ " - port %d", port->number); - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) { - return (port->bulk_out_size); - } - } + if (serial->num_bulk_out) + if (port->write_urb->status == -EINPROGRESS) + chars = port->write_urb->transfer_buffer_length; - return (0); + dbg (__FUNCTION__ " - returns %d", chars); + return (chars); } @@ -844,9 +846,10 @@ static void generic_read_bulk_callback (struct urb *urb) unsigned char *data = urb->transfer_buffer; int i; - dbg (__FUNCTION__ " - enter"); + dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } @@ -877,8 +880,6 @@ static void generic_read_bulk_callback (struct urb *urb) if (usb_submit_urb(urb)) dbg(__FUNCTION__ " - failed resubmitting read urb"); - dbg (__FUNCTION__ " - exit"); - return; } @@ -887,11 +888,11 @@ static void generic_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - struct tty_struct *tty; - dbg (__FUNCTION__ " - enter"); + dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } @@ -900,18 +901,36 @@ static void generic_write_bulk_callback (struct urb *urb) return; } + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return; +} + + +static void port_softint(void *private) +{ + struct usb_serial_port *port = (struct usb_serial_port *)private; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct tty_struct *tty; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + return; + } + tty = port->tty; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { + dbg(__FUNCTION__ " - write wakeup call."); (tty->ldisc.write_wakeup)(tty); + } wake_up_interruptible(&tty->write_wait); - - dbg (__FUNCTION__ " - exit"); - - return; } + static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_serial *serial = NULL; @@ -1117,6 +1136,8 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) port->number = i + serial->minor; port->serial = serial; port->magic = USB_SERIAL_PORT_MAGIC; + port->tqueue.routine = port_softint; + port->tqueue.data = port; } /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 8be2dd35181f..fa7f475c64ea 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -11,6 +11,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (06/25/2000) gkh + * Fixed bug in visor_unthrottle that should help with the disconnect in PPP + * bug that people have been reporting. + * * (06/23/2000) gkh * Cleaned up debugging statements in a quest to find UHCI timeout bug. * @@ -137,7 +141,7 @@ static void visor_unthrottle (struct usb_serial_port *port) { dbg(__FUNCTION__ " - port %d", port->number); - if (usb_unlink_urb (port->read_urb)) + if (usb_submit_urb (port->read_urb)) dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); return; diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c index d42448fbf8b0..019a86a8e2ef 100644 --- a/drivers/video/sisfb.c +++ b/drivers/video/sisfb.c @@ -175,9 +175,9 @@ static struct board { const char *name; } dev_list[] = { { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540, "SIS 540"}, { - PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, "SIS 630"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5300, "SIS 540"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_6300, "SIS 630"}, { 0, 0, NULL} }; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 5e49df10bde6..38f16f061b84 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -666,9 +666,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) interpreter, &interp_load_addr); - lock_kernel(); + allow_write_access(interpreter); fput(interpreter); - unlock_kernel(); kfree(elf_interpreter); if (elf_entry == ~0UL) { @@ -755,9 +754,8 @@ out: /* error cleanup */ out_free_dentry: - lock_kernel(); + allow_write_access(interpreter); fput(interpreter); - unlock_kernel(); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index 1b18094eb68e..95c24a70a3d9 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -17,6 +17,7 @@ #include #include #include +#include #define EM86_INTERP "/usr/bin/em86" @@ -43,6 +44,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) } bprm->sh_bang++; /* Well, the bang-shell is implicit... */ + allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 0d44c3d4ed2a..f9c30df1bc15 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -201,6 +201,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (!fmt) goto _ret; + allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index dc78f8389c26..3d5023e2d634 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -29,6 +29,7 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) */ bprm->sh_bang++; + allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/block_dev.c b/fs/block_dev.c index c455a735d769..3938e851f95e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -597,6 +597,8 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) ret = bdev->bd_op->open(fake_inode, &fake_file); if (!ret) atomic_inc(&bdev->bd_openers); + else if (!atomic_read(&bdev->bd_openers)) + bdev->bd_op = NULL; iput(fake_inode); } } @@ -617,6 +619,8 @@ int blkdev_open(struct inode * inode, struct file * filp) ret = bdev->bd_op->open(inode,filp); if (!ret) atomic_inc(&bdev->bd_openers); + else if (!atomic_read(&bdev->bd_openers)) + bdev->bd_op = NULL; } up(&bdev->bd_sem); return ret; diff --git a/fs/buffer.c b/fs/buffer.c index 47d690fa4463..fe7a36d2e6aa 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -360,12 +360,7 @@ asmlinkage long sys_fsync(unsigned int fd) goto out; dentry = file->f_dentry; - if (!dentry) - goto out_putf; - inode = dentry->d_inode; - if (!inode) - goto out_putf; err = -EINVAL; if (!file->f_op || !file->f_op->fsync) @@ -395,12 +390,7 @@ asmlinkage long sys_fdatasync(unsigned int fd) goto out; dentry = file->f_dentry; - if (!dentry) - goto out_putf; - inode = dentry->d_inode; - if (!inode) - goto out_putf; err = -EINVAL; if (!file->f_op || !file->f_op->fsync) @@ -2101,6 +2091,7 @@ static int grow_buffers(int size) spin_unlock(&free_list[isize].lock); page->buffers = bh; + page->flags &= ~(1 << PG_referenced); lru_cache_add(page); atomic_inc(&buffermem_pages); return 1; diff --git a/fs/exec.c b/fs/exec.c index 2ab337341ce6..ce1031e3b0dd 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -101,37 +101,54 @@ static inline void put_binfmt(struct linux_binfmt * fmt) */ asmlinkage long sys_uselib(const char * library) { - int fd, retval; struct file * file; + struct nameidata nd; + int error; - fd = sys_open(library, 0, 0); - if (fd < 0) - return fd; - file = fget(fd); - retval = -ENOEXEC; - if (file) { - if(file->f_op && file->f_op->read) { - struct linux_binfmt * fmt; + error = user_path_walk(library, &nd); + if (error) + goto out; - read_lock(&binfmt_lock); - for (fmt = formats ; fmt ; fmt = fmt->next) { - if (!fmt->load_shlib) - continue; - if (!try_inc_mod_count(fmt->module)) - continue; - read_unlock(&binfmt_lock); - retval = fmt->load_shlib(file); - read_lock(&binfmt_lock); - put_binfmt(fmt); - if (retval != -ENOEXEC) - break; - } + error = -EINVAL; + if (!S_ISREG(nd.dentry->d_inode->i_mode)) + goto exit; + + error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC); + if (error) + goto exit; + + lock_kernel(); + file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + unlock_kernel(); + error = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + + error = -ENOEXEC; + if(file->f_op && file->f_op->read) { + struct linux_binfmt * fmt; + + read_lock(&binfmt_lock); + for (fmt = formats ; fmt ; fmt = fmt->next) { + if (!fmt->load_shlib) + continue; + if (!try_inc_mod_count(fmt->module)) + continue; read_unlock(&binfmt_lock); + error = fmt->load_shlib(file); + read_lock(&binfmt_lock); + put_binfmt(fmt); + if (error != -ENOEXEC) + break; } - fput(file); + read_unlock(&binfmt_lock); } - sys_close(fd); - return retval; + fput(file); +out: + return error; +exit: + path_release(&nd); + goto out; } /* @@ -319,6 +336,7 @@ int setup_arg_pages(struct linux_binprm *bprm) struct file *open_exec(const char *name) { struct nameidata nd; + struct inode *inode; struct file *file; int err = 0; @@ -328,14 +346,22 @@ struct file *open_exec(const char *name) unlock_kernel(); file = ERR_PTR(err); if (!err) { + inode = nd.dentry->d_inode; file = ERR_PTR(-EACCES); - if (S_ISREG(nd.dentry->d_inode->i_mode)) { - int err = permission(nd.dentry->d_inode, MAY_EXEC); + if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) { + int err = permission(inode, MAY_EXEC); file = ERR_PTR(err); if (!err) { lock_kernel(); file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); unlock_kernel(); + if (!IS_ERR(file)) { + err = deny_write_access(file); + if (err) { + fput(file); + file = ERR_PTR(err); + } + } out: return file; } @@ -540,23 +566,13 @@ static inline int must_not_trace_exec(struct task_struct * p) int prepare_binprm(struct linux_binprm *bprm) { int mode; - int retval,id_change,cap_raised; + int id_change,cap_raised; struct inode * inode = bprm->file->f_dentry->d_inode; mode = inode->i_mode; - if (!S_ISREG(mode)) /* must be regular file */ - return -EACCES; - if (!(mode & 0111)) /* with at least _one_ execute bit set */ + /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */ + if (!(mode & 0111)) /* with at least _one_ execute bit set */ return -EACCES; - if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */ - return -EACCES; - if (!inode->i_sb) - return -EACCES; - if ((retval = permission(inode, MAY_EXEC)) != 0) - return retval; - /* better not execute files which are being written to */ - if (atomic_read(&inode->i_writecount) > 0) - return -ETXTBSY; bprm->e_uid = current->euid; bprm->e_gid = current->egid; @@ -728,6 +744,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) char * dynloader[] = { "/sbin/loader" }; struct file * file; + allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; @@ -761,6 +778,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) retval = fn(bprm, regs); if (retval >= 0) { put_binfmt(fmt); + allow_write_access(bprm->file); if (bprm->file) fput(bprm->file); bprm->file = NULL; @@ -822,11 +840,13 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) { + allow_write_access(file); fput(file); return bprm.argc; } if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { + allow_write_access(file); fput(file); return bprm.envc; } @@ -855,6 +875,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs out: /* Something went wrong, return the inode and free the argument pages*/ + allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index aa6a599fc0a5..d3af3b99239b 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -593,7 +593,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, /* * set up enough so that it can read an inode */ - sb->s_dev = dev; sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); if (!sb->s_root) { diff --git a/fs/fcntl.c b/fs/fcntl.c index f6e4e1651a27..37e32a0126b9 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -252,8 +252,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) err = sock_fcntl (filp, cmd, arg); break; } - fput(filp); unlock_kernel(); + fput(filp); out: return err; } diff --git a/fs/file_table.c b/fs/file_table.c index ecaa4689677f..5c722143dffc 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -16,9 +16,7 @@ static kmem_cache_t *filp_cache; /* sysctl tunables... */ -int nr_files; /* read only */ -int nr_free_files; /* read only */ -int max_files = NR_FILE;/* tunable */ +struct files_stat_struct files_stat = {0, 0, NR_FILE}; /* Here the new files go */ static LIST_HEAD(anon_list); @@ -53,11 +51,11 @@ struct file * get_empty_filp(void) struct file * f; file_list_lock(); - if (nr_free_files > NR_RESERVED_FILES) { + if (files_stat.nr_free_files > NR_RESERVED_FILES) { used_one: f = list_entry(free_list.next, struct file, f_list); list_del(&f->f_list); - nr_free_files--; + files_stat.nr_free_files--; new_one: file_list_unlock(); memset(f, 0, sizeof(*f)); @@ -73,25 +71,25 @@ struct file * get_empty_filp(void) /* * Use a reserved one if we're the superuser */ - if (nr_free_files && !current->euid) + if (files_stat.nr_free_files && !current->euid) goto used_one; /* * Allocate a new one if we're below the limit. */ - if (nr_files < max_files) { + if (files_stat.nr_files < files_stat.max_files) { file_list_unlock(); f = kmem_cache_alloc(filp_cache, SLAB_KERNEL); file_list_lock(); if (f) { - nr_files++; + files_stat.nr_files++; goto new_one; } /* Big problems... */ printk("VFS: filp allocation failed\n"); - } else if (max_files > old_max) { - printk("VFS: file-max limit %d reached\n", max_files); - old_max = max_files; + } else if (files_stat.max_files > old_max) { + printk("VFS: file-max limit %d reached\n", files_stat.max_files); + old_max = files_stat.max_files; } file_list_unlock(); return NULL; @@ -148,7 +146,7 @@ void _fput(struct file *file) file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); - nr_free_files++; + files_stat.nr_free_files++; file_list_unlock(); } @@ -160,7 +158,7 @@ void put_filp(struct file *file) file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); - nr_free_files++; + files_stat.nr_free_files++; file_list_unlock(); } } diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index b09ad98eacc6..5684801df2a1 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -330,7 +330,15 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) struct iattr newattrs; int err; hpfs_unlock_2inodes(dir, inode); - if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret; + if (rep) + goto ret; + d_drop(dentry); + if (dentry->d_count > 1 || + permission(inode, MAY_WRITE) || + get_write_access(inode)) { + d_rehash(dentry); + goto ret; + } /*printk("HPFS: truncating file before delete.\n");*/ down(&inode->i_sem); newattrs.ia_size = 0; diff --git a/fs/ioctl.c b/fs/ioctl.c index 16ad5ec267c3..f02d766bd378 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -107,8 +107,8 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) else if (filp->f_op && filp->f_op->ioctl) error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); } - fput(filp); unlock_kernel(); + fput(filp); out: return error; diff --git a/fs/namei.c b/fs/namei.c index 501000381024..fcda2fd6162a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -89,6 +89,12 @@ * if the pathname has trailing slashes - follow. * otherwise - don't follow. * (applied in that order). + * + * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT + * restored for 2.4. This is the last surviving part of old 4.2BSD bug. + * During the 2.4 we need to fix the userland stuff depending on it - + * hopefully we will be able to get rid of that wart in 2.5. So far only + * XEmacs seems to be relying on it... */ /* In order to reduce some races, while at the same time doing additional @@ -191,21 +197,35 @@ int permission(struct inode * inode,int mask) * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist * > 0: (i_writecount) users are writing to the file. * - * WARNING: as soon as we will move get_write_access(), do_mmap() or - * prepare_binfmt() out of the big lock we will need a spinlock protecting - * the checks in all 3. For the time being it is not needed. + * Normally we operate on that counter with atomic_{inc,dec} and it's safe + * except for the cases where we don't hold i_writecount yet. Then we need to + * use {get,deny}_write_access() - these functions check the sign and refuse + * to do the change if sign is wrong. Exclusion between them is provided by + * spinlock (arbitration_lock) and I'll rip the second arsehole to the first + * who will try to move it in struct inode - just leave it here. */ +static spinlock_t arbitration_lock = SPIN_LOCK_UNLOCKED; int get_write_access(struct inode * inode) { - if (atomic_read(&inode->i_writecount) < 0) + spin_lock(&arbitration_lock); + if (atomic_read(&inode->i_writecount) < 0) { + spin_unlock(&arbitration_lock); return -ETXTBSY; + } atomic_inc(&inode->i_writecount); + spin_unlock(&arbitration_lock); return 0; } - -void put_write_access(struct inode * inode) +int deny_write_access(struct file * file) { - atomic_dec(&inode->i_writecount); + spin_lock(&arbitration_lock); + if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) { + spin_unlock(&arbitration_lock); + return -ETXTBSY; + } + atomic_dec(&file->f_dentry->d_inode->i_writecount); + spin_unlock(&arbitration_lock); + return 0; } void path_release(struct nameidata *nd) @@ -337,7 +357,34 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) { return __follow_down(mnt,dentry); } - + +static inline void follow_dotdot(struct nameidata *nd) +{ + while(1) { + struct vfsmount *parent; + struct dentry *dentry; + if (nd->dentry == current->fs->root && + nd->mnt == current->fs->rootmnt) { + break; + } + if (nd->dentry != nd->mnt->mnt_root) { + dentry = dget(nd->dentry->d_parent); + dput(nd->dentry); + nd->dentry = dentry; + break; + } + parent=nd->mnt->mnt_parent; + if (parent == nd->mnt) { + break; + } + mntget(parent); + dentry=dget(nd->mnt->mnt_mountpoint); + dput(nd->dentry); + nd->dentry = dentry; + mntput(nd->mnt); + nd->mnt = parent; + } +} /* * Name resolution. * @@ -403,19 +450,7 @@ int path_walk(const char * name, struct nameidata *nd) case 2: if (this.name[1] != '.') break; - while (1) { - if (nd->dentry == current->fs->root && - nd->mnt == current->fs->rootmnt) - break; - if (nd->dentry != nd->mnt->mnt_root) { - dentry = dget(nd->dentry->d_parent); - dput(nd->dentry); - nd->dentry = dentry; - break; - } - if (!__follow_up(&nd->mnt, &nd->dentry)) - break; - } + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -483,19 +518,7 @@ last_component: case 2: if (this.name[1] != '.') break; - while (1) { - if (nd->dentry == current->fs->root && - nd->mnt == current->fs->rootmnt) - break; - if (nd->dentry != nd->mnt->mnt_root) { - dentry = dget(nd->dentry->d_parent); - dput(nd->dentry); - nd->dentry = dentry; - break; - } - if (!__follow_up(&nd->mnt, &nd->dentry)) - break; - } + follow_dotdot(nd); inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -771,8 +794,6 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; - if (IS_DEADDIR(dir)) - return -ENOENT; error = permission(dir,MAY_WRITE | MAY_EXEC); if (error) return error; @@ -786,8 +807,6 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) return -ENOTDIR; if (IS_ROOT(victim)) return -EBUSY; - if (d_mountpoint(victim)) - return -EBUSY; } else if (S_ISDIR(victim->d_inode->i_mode)) return -EISDIR; return 0; @@ -872,83 +891,92 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) int acc_mode, error = 0; struct inode *inode; struct dentry *dentry; + struct dentry *dir; + int count = 0; acc_mode = ACC_MODE(flag); + + /* + * The simplest case - just a plain lookup. + */ if (!(flag & O_CREAT)) { if (path_init(pathname, lookup_flags(flag), nd)) error = path_walk(pathname, nd); if (error) return error; - dentry = nd->dentry; - } else { - struct dentry *dir; + goto ok; + } - if (path_init(pathname, LOOKUP_PARENT, nd)) - error = path_walk(pathname, nd); + /* + * Create - we need to know the parent. + */ + if (path_init(pathname, LOOKUP_PARENT, nd)) + error = path_walk(pathname, nd); + if (error) + return error; + + /* + * We have the parent and last component. First of all, check + * that we are not asked to creat(2) an obvious directory - that + * will not do. + */ + error = -EISDIR; + if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len]) + goto exit; + + dir = nd->dentry; + down(&dir->d_inode->i_sem); + dentry = lookup_hash(&nd->last, nd->dentry); + +do_last: + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) { + up(&dir->d_inode->i_sem); + goto exit; + } + + /* Negative dentry, just create the file */ + if (!dentry->d_inode) { + error = vfs_create(dir->d_inode, dentry, mode); + up(&dir->d_inode->i_sem); + dput(nd->dentry); + nd->dentry = dentry; if (error) - return error; - /* - * It's not obvious that open(".", O_CREAT, foo) should - * fail, but it's even less obvious that it should succeed. - * Since O_CREAT means an intention to create the thing and - * open(2) had never created directories, count it as caller's - * luserdom and let him sod off - -EISDIR it is. - */ - error = -EISDIR; - if (nd->last_type != LAST_NORM) - goto exit; - /* same for foo/ */ - if (nd->last.name[nd->last.len]) goto exit; + /* Don't check for write permission, don't truncate */ + acc_mode = 0; + flag &= ~O_TRUNC; + goto ok; + } - dir = nd->dentry; - down(&dir->d_inode->i_sem); + /* + * It already exists. + */ + up(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - up(&dir->d_inode->i_sem); - goto exit; - } + error = -EEXIST; + if (flag & O_EXCL) + goto exit_dput; - if (dentry->d_inode) { - up(&dir->d_inode->i_sem); - error = -EEXIST; - if (flag & O_EXCL) - goto exit_dput; - if (dentry->d_inode->i_op && - dentry->d_inode->i_op->follow_link) { - /* - * With O_EXCL it would be -EEXIST. - * If symlink is a dangling one it's -ENOENT. - * Otherwise we open the object it points to. - */ - error = do_follow_link(dentry, nd); - dput(dentry); - if (error) - return error; - dentry = nd->dentry; - } else { - dput(nd->dentry); - nd->dentry = dentry; - } - error = -EISDIR; - if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) - goto exit; - } else { - error = vfs_create(dir->d_inode, dentry, mode); - up(&dir->d_inode->i_sem); - /* Don't check for write permission, don't truncate */ - acc_mode = 0; - flag &= ~O_TRUNC; - dput(nd->dentry); - nd->dentry = dentry; - if (error) - goto exit; - } + if (d_mountpoint(dentry)) { + error = -ELOOP; + if (flag & O_NOFOLLOW) + goto exit_dput; + do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry)); } + error = -ENOENT; + if (!dentry->d_inode) + goto exit_dput; + if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) + goto do_link; + dput(nd->dentry); + nd->dentry = dentry; + error = -EISDIR; + if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) + goto exit; +ok: error = -ENOENT; inode = dentry->d_inode; if (!inode) @@ -1023,6 +1051,47 @@ exit_dput: exit: path_release(nd); return error; + +do_link: + error = -ELOOP; + if (flag & O_NOFOLLOW) + goto exit_dput; + /* + * This is subtle. Instead of calling do_follow_link() we do the + * thing by hands. The reason is that this way we have zero link_count + * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT. + * After that we have the parent and last component, i.e. + * we are in the same situation as after the first path_walk(). + * Well, almost - if the last component is normal we get its copy + * stored in nd->last.name and we will have to putname() it when we + * are done. Procfs-like symlinks just set LAST_BIND. + */ + UPDATE_ATIME(dentry->d_inode); + error = dentry->d_inode->i_op->follow_link(dentry, nd); + dput(dentry); + if (error) + return error; + if (nd->last_type == LAST_BIND) { + dentry = nd->dentry; + goto ok; + } + error = -EISDIR; + if (nd->last_type != LAST_NORM) + goto exit; + if (nd->last.name[nd->last.len]) { + putname(nd->last.name); + goto exit; + } + if (count++==32) { + dentry = nd->dentry; + putname(nd->last.name); + goto ok; + } + dir = nd->dentry; + down(&dir->d_inode->i_sem); + dentry = lookup_hash(&nd->last, nd->dentry); + putname(nd->last.name); + goto do_last; } static struct dentry *lookup_create(struct nameidata *nd, int is_dir) @@ -1213,9 +1282,15 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); d_unhash(dentry); - error = dir->i_op->rmdir(dir, dentry); - if (!error) - dentry->d_inode->i_flags |= S_DEAD; + if (IS_DEADDIR(dir)) + error = -ENOENT; + else if (d_mountpoint(dentry)) + error = -EBUSY; + else { + error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; + } double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); if (!error) d_delete(dentry); @@ -1275,9 +1350,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) error = -EPERM; if (dir->i_op && dir->i_op->unlink) { DQUOT_INIT(dir); - error = dir->i_op->unlink(dir, dentry); - if (!error) - d_delete(dentry); + if (d_mountpoint(dentry)) + error = -EBUSY; + else { + error = dir->i_op->unlink(dir, dentry); + if (!error) + d_delete(dentry); + } } } up(&dir->i_zombie); @@ -1555,7 +1634,12 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, } else double_down(&old_dir->i_zombie, &new_dir->i_zombie); - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); + if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir)) + error = -ENOENT; + else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) + error = -EBUSY; + else + error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (target) { if (!error) target->i_flags |= S_DEAD; @@ -1603,7 +1687,10 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); double_down(&old_dir->i_zombie, &new_dir->i_zombie); - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); + if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) + error = -EBUSY; + else + error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); double_up(&old_dir->i_zombie, &new_dir->i_zombie); if (error) return error; @@ -1734,6 +1821,8 @@ out: static inline int __vfs_follow_link(struct nameidata *nd, const char *link) { + int res = 0; + char *name; if (IS_ERR(link)) goto fail; @@ -1741,10 +1830,25 @@ __vfs_follow_link(struct nameidata *nd, const char *link) path_release(nd); if (!walk_init_root(link, nd)) /* weird __emul_prefix() stuff did it */ - return 0; + goto out; } - return path_walk(link, nd); - + res = path_walk(link, nd); +out: + if (current->link_count || res || nd->last_type!=LAST_NORM) + return res; + /* + * If it is an iterative symlinks resolution in open_namei() we + * have to copy the last component. And all that crap because of + * bloody create() on broken symlinks. Furrfu... + */ + name = __getname(); + if (IS_ERR(name)) + goto fail_name; + strcpy(name, nd->last.name); + nd->last.name = name; + return 0; +fail_name: + link = name; fail: path_release(nd); return PTR_ERR(link); diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index dee52dd8afc7..df2532048814 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -9,8 +9,6 @@ * creates a client control block and adds it to the hash * table. Then, you call NFSCTL_EXPORT for each fs. * - * You cannot currently read the export information from the - * kernel. It would be nice to have a /proc file though. * * Copyright (C) 1995, 1996 Olaf Kirch, */ @@ -388,12 +386,10 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, err = -EPERM; if (path) { - err = 0; - if (path_init(path, LOOKUP_POSITIVE, &nd)) - err = path_walk(path, &nd); - if (err) { + if (path_init(path, LOOKUP_POSITIVE, &nd) && + path_walk(path, &nd)) { printk("nfsd: exp_rootfh path not found %s", path); - return -EPERM; + return err; } dev = nd.dentry->d_inode->i_dev; ino = nd.dentry->d_inode->i_ino; @@ -438,7 +434,8 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, fh_put(&fh); out: - path_release(&nd); + if (path) + path_release(&nd); return err; } diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 357a297f6648..f5795583bd8c 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -174,8 +174,9 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp, int type) { struct svc_cacherep *rh, *rp; - struct svc_client *clp = rqstp->rq_client; u32 xid = rqstp->rq_xid, + proto = rqstp->rq_prot, + vers = rqstp->rq_vers, proc = rqstp->rq_proc; unsigned long age; @@ -189,7 +190,9 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) while ((rp = rp->c_hash_next) != rh) { if (rp->c_state != RC_UNUSED && xid == rp->c_xid && proc == rp->c_proc && - exp_checkaddr(clp, rp->c_client)) { + proto == rp->c_prot && vers == rp->c_vers && + time_before(jiffies, rp->c_timestamp + 120*HZ) && + memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) { nfsdstats.rchits++; goto found_entry; } @@ -226,7 +229,11 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) rp->c_state = RC_INPROG; rp->c_xid = xid; rp->c_proc = proc; - rp->c_client = rqstp->rq_addr.sin_addr; + rp->c_addr = rqstp->rq_addr; + rp->c_prot = proto; + rp->c_vers = vers; + rp->c_timestamp = jiffies; + hash_refile(rp); /* release any buffer */ diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c4e4561859a5..913cbf5f8e7d 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -5,7 +5,6 @@ * * Copyright (C) 1995, 1996 Olaf Kirch */ -#define NFS_GETFH_NEW #include #include diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 85a98c874070..78f399bd37b0 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -495,17 +495,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); - if (!fhp->fh_dverified) { + if (!fhp->fh_dentry) { kdev_t xdev; ino_t xino; __u32 *datap=NULL; int data_left = fh->fh_size/4; int nfsdev; error = nfserr_stale; -#if CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) error = nfserr_badhandle; -#endif if (fh->fh_version == 1) { datap = fh->fh_auth; @@ -562,10 +560,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) * Look up the dentry using the NFS file handle. */ error = nfserr_stale; -#if CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) error = nfserr_badhandle; -#endif if (fh->fh_version == 1) { /* if fileid_type != 0, and super_operations provide fh_to_dentry lookup, @@ -611,7 +607,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) fhp->fh_dentry = dentry; fhp->fh_export = exp; - fhp->fh_dverified = 1; nfsd_nr_verified++; } else { /* just rechecking permissions @@ -731,7 +726,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry) parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); - if (fhp->fh_dverified || fhp->fh_locked || fhp->fh_dentry) { + if (fhp->fh_locked || fhp->fh_dentry) { printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n", parent->d_name.name, dentry->d_name.name); } @@ -757,8 +752,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry) fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4; - /* We stuck it there, we know it's good. */ - fhp->fh_dverified = 1; nfsd_nr_verified++; if (fhp->fh_handle.fh_fileid_type == 255) return nfserr_opnotsupp; @@ -775,7 +768,7 @@ fh_update(struct svc_fh *fhp) struct dentry *dentry; __u32 *datap; - if (!fhp->fh_dverified) + if (!fhp->fh_dentry) goto out_bad; dentry = fhp->fh_dentry; @@ -811,10 +804,9 @@ void fh_put(struct svc_fh *fhp) { struct dentry * dentry = fhp->fh_dentry; - if (fhp->fh_dverified) { + if (dentry) { fh_unlock(fhp); fhp->fh_dentry = NULL; - fhp->fh_dverified = 0; dput(dentry); nfsd_nr_put++; } diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 763970736e50..b5057d57b5f4 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -239,7 +239,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, * whether the file exists or not. Time to bail ... */ nfserr = nfserr_acces; - if (!newfhp->fh_dverified) { + if (!newfhp->fh_dentry) { printk(KERN_WARNING "nfsd_proc_create: file handle not verified\n"); goto out_unlock; @@ -415,7 +415,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, dprintk("nfsd: MKDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name); - if (resp->fh.fh_dverified) { + if (resp->fh.fh_dentry) { printk(KERN_WARNING "nfsd_proc_mkdir: response already verified??\n"); } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index fb3b32f8de56..9a4d12a7d244 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -275,7 +275,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) /* Encode result. * For NFSv2, additional info is never returned in case of an error. */ -#ifdef CONFIG_NFSD_V3 if (!(nfserr && rqstp->rq_vers == 2)) { xdr = proc->pc_encode; if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { @@ -286,17 +285,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) return 1; } } -#else - xdr = proc->pc_encode; - if (!nfserr && xdr - && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) { - /* Failed to encode result. Release cache entry */ - dprintk("nfsd: failed to encode result!\n"); - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); - *statp = rpc_system_err; - return 1; - } -#endif /* CONFIG_NFSD_V3 */ /* Store reply in cache. */ nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 40f1ab85aa2c..79bceeb860c2 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -165,6 +165,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, dentry = mounts; } else dput(mounts); + mntput(mnt); } } /* @@ -253,8 +254,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) goto out_nfserr; err = locks_verify_truncate(inode, NULL, iap->ia_size); - if (err) + if (err) { + put_write_access(inode); goto out_nfserr; + } DQUOT_INIT(inode); } @@ -316,9 +319,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) if (EX_ISSYNC(fhp->fh_export)) write_inode_now(inode); err = 0; - - /* Don't unlock inode; the nfssvc_release functions are supposed - * to do this. */ out: return err; @@ -413,7 +413,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access) out: return error; } -#endif +#endif /* CONFIG_NFSD_V3 */ @@ -598,7 +598,6 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, oldfs = get_fs(); set_fs(KERNEL_DS); err = file.f_op->read(&file, buf, *count, &file.f_pos); set_fs(oldfs); - nfsdstats.io_read += *count; /* Write back readahead params */ if (ra != NULL) { @@ -614,6 +613,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, } if (err >= 0) { + nfsdstats.io_read += err; *count = err; err = 0; } else @@ -665,19 +665,16 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, * When gathered writes have been configured for this volume, * flushing the data to disk is handled separately below. */ -#ifdef CONFIG_NFSD_V3 + if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */ stable = 2; *stablep = 2; /* FILE_SYNC */ } + if (!EX_ISSYNC(exp)) stable = 0; if (stable && !EX_WGATHER(exp)) file.f_flags |= O_SYNC; -#else - if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp)) - file.f_flags |= O_SYNC; -#endif /* CONFIG_NFSD_V3 */ file.f_pos = offset; /* set write offset */ @@ -692,7 +689,8 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, #else err = file.f_op->write(&file, buf, cnt, &file.f_pos); #endif - nfsdstats.io_write += cnt; + if (err >= 0) + nfsdstats.io_write += cnt; set_fs(oldfs); /* clear setuid/setgid flag after write */ @@ -734,7 +732,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, #else dprintk("nfsd: write defer %d\n", current->pid); /* FIXME: Olaf commented this out [gam3] */ + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); + current->state = TASK_RUNNING; dprintk("nfsd: write resume %d\n", current->pid); #endif } @@ -743,7 +743,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, dprintk("nfsd: write sync %d\n", current->pid); nfsd_sync(&file); } +#if 0 wake_up(&inode->i_wait); +#endif last_ino = inode->i_ino; last_dev = inode->i_dev; } @@ -762,11 +764,12 @@ out: #ifdef CONFIG_NFSD_V3 /* - * Commit all pendig writes to stable storage. - * Strictly speaking, we could sync just indicated the file region here, + * Commit all pending writes to stable storage. + * Strictly speaking, we could sync just the indicated file region here, * but there's currently no way we can ask the VFS to do so. * - * We lock the file to make sure we return full WCC data to the client. + * Unfortunately we cannot lock the file to make sure we return full WCC + * data to the client, as locking happens lower down in the filesystem. */ int nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, @@ -828,7 +831,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, * Check whether the response file handle has been verified yet. * If it has, the parent directory should already be locked. */ - if (!resfhp->fh_dverified) { + if (!resfhp->fh_dentry) { /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ fh_lock(fhp); dchild = lookup_one(fname, dentry); @@ -928,6 +931,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, struct dentry *dentry, *dchild; struct inode *dirp; int err; + __u32 v_mtime=0, v_atime=0; + int v_mode=0; err = nfserr_perm; if (!flen) @@ -963,6 +968,19 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, if (err) goto out; + if (createmode == NFS3_CREATE_EXCLUSIVE) { + /* while the verifier would fit in mtime+atime, + * solaris7 gets confused (bugid 4218508) if these have + * the high bit set, so we use the mode as well + */ + v_mtime = verifier[0]&0x7fffffff; + v_atime = verifier[1]&0x7fffffff; + v_mode = S_IFREG + | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */ + | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */ + ; + } + if (dchild->d_inode) { err = 0; @@ -976,10 +994,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, } break; case NFS3_CREATE_EXCLUSIVE: - if ( dchild->d_inode->i_mtime == verifier[0] - && dchild->d_inode->i_atime == verifier[1] - && dchild->d_inode->i_mode == S_IFREG - && dchild->d_inode->i_size == 0 ) + if ( dchild->d_inode->i_mtime == v_mtime + && dchild->d_inode->i_atime == v_atime + && dchild->d_inode->i_mode == v_mode + && dchild->d_inode->i_size == 0 ) break; /* fallthru */ case NFS3_CREATE_GUARDED: @@ -1005,19 +1023,23 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; if (createmode == NFS3_CREATE_EXCLUSIVE) { - /* Cram the verifier into atime/mtime */ - iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET; - iap->ia_mtime = verifier[0]; - iap->ia_atime = verifier[1]; + /* Cram the verifier into atime/mtime/mode */ + iap->ia_valid = ATTR_MTIME|ATTR_ATIME + | ATTR_MTIME_SET|ATTR_ATIME_SET + | ATTR_MODE; + iap->ia_mtime = v_mtime; + iap->ia_atime = v_atime; + iap->ia_mode = v_mode; } - /* Set file attributes. Mode has already been set and - * setting uid/gid works only for root. Irix appears to - * send along the gid when it tries to implement setgid - * directories via NFS. Clear out all that cruft. + /* Set file attributes. + * Mode has already been set but we might need to reset it + * for CREATE_EXCLUSIVE + * Irix appears to send along the gid when it tries to + * implement setgid directories via NFS. Clear out all that cruft. */ set_attr: - if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) + if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) err = nfsd_setattr(rqstp, resfhp, iap); out: @@ -1230,7 +1252,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) goto out; + /* cannot use fh_lock as we need deadlock protective ordering + * so do it by hand */ double_down(&tdir->i_sem, &fdir->i_sem); + ffhp->fh_locked = tfhp->fh_locked = 1; + fill_pre_wcc(ffhp); + fill_pre_wcc(tfhp); + odentry = lookup_one(fname, fdentry); err = PTR_ERR(odentry); if (IS_ERR(odentry)) @@ -1245,39 +1273,31 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (IS_ERR(ndentry)) goto out_dput_old; -#ifdef CONFIG_NFSD_V3 - /* Fill in the pre-op attr for the wcc data for both - * tdir and fdir - */ - fill_pre_wcc(ffhp); - fill_pre_wcc(tfhp); -#endif /* CONFIG_NFSD_V3 */ err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { nfsd_sync_dir(tdentry); nfsd_sync_dir(fdentry); } -#ifdef CONFIG_NFSD_V3 - /* Fill in the post-op attr for the wcc data for both - * tdir and fdir - */ - fill_post_wcc(ffhp); - fill_post_wcc(tfhp); -#endif /* CONFIG_NFSD_V3 */ - double_up(&tdir->i_sem, &fdir->i_sem); dput(ndentry); -out_dput_old: + out_dput_old: dput(odentry); + out_nfserr: if (err) - goto out_nfserr; + err = nfserrno(err); + + /* we cannot reply on fh_unlock on the two filehandles, + * as that would do the wrong thing if the two directories + * were the same, so again we do it by hand + */ + fill_post_wcc(ffhp); + fill_post_wcc(tfhp); + double_up(&tdir->i_sem, &fdir->i_sem); + ffhp->fh_locked = tfhp->fh_locked = 0; + out: return err; - -out_nfserr: - err = nfserrno(err); - goto out; } /* @@ -1320,17 +1340,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, err = vfs_rmdir(dirp, rdentry); } - fh_unlock(fhp); - dput(rdentry); if (err) goto out_nfserr; - if (EX_ISSYNC(fhp->fh_export)) { - down(&dentry->d_inode->i_sem); + if (EX_ISSYNC(fhp->fh_export)) nfsd_sync_dir(dentry); - up(&dentry->d_inode->i_sem); - } + out: return err; @@ -1353,13 +1369,11 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, struct file file; struct readdir_cd cd; - err = 0; - if (offset > ~(u32) 0) - goto out; - err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); if (err) goto out; + if (offset > ~(u32) 0) + goto out_close; err = nfserr_notdir; if (!file.f_op->readdir) @@ -1402,11 +1416,9 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, eof = !cd.eob; if (cd.offset) { -#ifdef CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) (void)xdr_encode_hyper(cd.offset, file.f_pos); else -#endif /* CONFIG_NFSD_V3 */ *cd.offset = htonl(file.f_pos); } diff --git a/fs/pipe.c b/fs/pipe.c index b97851fab7be..a30985a538ba 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -607,6 +607,8 @@ static struct super_block * pipefs_read_super(struct super_block *sb, void *data root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_uid = root->i_gid = 0; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; + root->i_sb = sb; + root->i_dev = sb->s_dev; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = PIPEFS_MAGIC; diff --git a/fs/proc/base.c b/fs/proc/base.c index fb63722d523a..383ef6019ef2 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -408,6 +408,7 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) goto out; error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt); + nd->last_type = LAST_BIND; out: #ifdef NULL_VFSMNT mntput(dummy); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 60393eb91a2c..3576482ca1a5 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -340,7 +340,6 @@ static struct super_block *qnx4_read_super(struct super_block *s, set_blocksize(dev, QNX4_BLOCK_SIZE); s->s_blocksize = QNX4_BLOCK_SIZE; s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS; - s->s_dev = dev; /* Check the boot signature. Since the qnx4 code is dangerous, we should leave as quickly as possible diff --git a/fs/super.c b/fs/super.c index 5b8974e5b0ef..cfc5c90613bf 100644 --- a/fs/super.c +++ b/fs/super.c @@ -260,7 +260,7 @@ int get_filesystem_list(char * buf) return len; } -static struct file_system_type *get_fs_type(const char *name) +struct file_system_type *get_fs_type(const char *name) { struct file_system_type *fs; @@ -281,14 +281,28 @@ static struct file_system_type *get_fs_type(const char *name) static LIST_HEAD(vfsmntlist); -static struct vfsmount *add_vfsmnt(struct super_block *sb, - struct dentry *mountpoint, +/** + * add_vfsmnt - add a new mount node + * @nd: location of mountpoint or %NULL if we want a root node + * @root: root of (sub)tree to be mounted + * @dev_name: device name to show in /proc/mounts + * + * This is VFS idea of mount. New node is allocated, bound to a tree + * we are mounting and optionally (OK, usually) registered as mounted + * on a given mountpoint. Returns a pointer to new node or %NULL in + * case of failure. + * + * Potential reason for failure (aside of trivial lack of memory) is a + * deleted mountpoint. Caller must hold ->i_zombie on mountpoint + * dentry (if any). + */ + +static struct vfsmount *add_vfsmnt(struct nameidata *nd, struct dentry *root, - struct vfsmount *parent, - const char *dev_name, - const char *dir_name) + const char *dev_name) { struct vfsmount *mnt; + struct super_block *sb = root->d_inode->i_sb; char *name; mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL); @@ -296,13 +310,7 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb, goto out; memset(mnt, 0, sizeof(struct vfsmount)); - atomic_set(&mnt->mnt_count,1); - mnt->mnt_sb = sb; - mnt->mnt_mountpoint = dget(mountpoint); - mnt->mnt_root = dget(root); - mnt->mnt_parent = parent ? mntget(parent) : mnt; - - /* N.B. Is it really OK to have a vfsmount without names? */ + /* It may be NULL, but who cares? */ if (dev_name) { name = kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (name) { @@ -310,51 +318,53 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb, mnt->mnt_devname = name; } } - name = kmalloc(strlen(dir_name)+1, GFP_KERNEL); - if (name) { - strcpy(name, dir_name); - mnt->mnt_dirname = name; - } mnt->mnt_owner = current->uid; + atomic_set(&mnt->mnt_count,1); + mnt->mnt_sb = sb; - if (parent) - list_add(&mnt->mnt_child, &parent->mnt_mounts); - else + if (nd && !IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) + goto fail; + mnt->mnt_root = dget(root); + mnt->mnt_mountpoint = nd ? dget(nd->dentry) : dget(root); + mnt->mnt_parent = nd ? mntget(nd->mnt) : mnt; + + if (nd) { + list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts); + list_add(&mnt->mnt_clash, &nd->dentry->d_vfsmnt); + } else { INIT_LIST_HEAD(&mnt->mnt_child); + INIT_LIST_HEAD(&mnt->mnt_clash); + } INIT_LIST_HEAD(&mnt->mnt_mounts); list_add(&mnt->mnt_instances, &sb->s_mounts); - list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); list_add(&mnt->mnt_list, vfsmntlist.prev); out: return mnt; +fail: + kfree(mnt->mnt_devname); + kfree(mnt); + return NULL; } static void move_vfsmnt(struct vfsmount *mnt, struct dentry *mountpoint, struct vfsmount *parent, - const char *dev_name, - const char *dir_name) + const char *dev_name) { - struct dentry *old_mountpoint = mnt->mnt_mountpoint; - struct vfsmount *old_parent = mnt->mnt_parent; - char *new_devname = NULL, *new_dirname = NULL; + struct dentry *old_mountpoint; + struct vfsmount *old_parent; + char *new_devname = NULL; if (dev_name) { new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (new_devname) strcpy(new_devname, dev_name); } - if (dir_name) { - new_dirname = kmalloc(strlen(dir_name)+1, GFP_KERNEL); - if (new_dirname) - strcpy(new_dirname, dir_name); - } + + old_mountpoint = mnt->mnt_mountpoint; + old_parent = mnt->mnt_parent; /* flip names */ - if (new_dirname) { - kfree(mnt->mnt_dirname); - mnt->mnt_dirname = new_dirname; - } if (new_devname) { kfree(mnt->mnt_devname); mnt->mnt_devname = new_devname; @@ -365,11 +375,13 @@ static void move_vfsmnt(struct vfsmount *mnt, mnt->mnt_parent = parent ? mntget(parent) : mnt; list_del(&mnt->mnt_clash); list_del(&mnt->mnt_child); - list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); - if (parent) + if (parent) { list_add(&mnt->mnt_child, &parent->mnt_mounts); - else + list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); + } else { INIT_LIST_HEAD(&mnt->mnt_child); + INIT_LIST_HEAD(&mnt->mnt_clash); + } /* put the old stuff */ dput(old_mountpoint); @@ -391,7 +403,6 @@ static void remove_vfsmnt(struct vfsmount *mnt) dput(mnt->mnt_mountpoint); dput(mnt->mnt_root); kfree(mnt->mnt_devname); - kfree(mnt->mnt_dirname); kfree(mnt); } @@ -738,10 +749,6 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, /* Done with lookups, semaphore down */ down(&mount_sem); dev = to_kdev_t(bdev->bd_dev); - check_disk_change(dev); - error = -EACCES; - if (!(flags & MS_RDONLY) && is_read_only(dev)) - goto out; sb = get_super(dev); if (sb) { if (fs_type == sb->s_type) { @@ -755,6 +762,10 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, error = blkdev_get(bdev, mode, 0, BDEV_FS); if (error) goto out; + check_disk_change(dev); + error = -EACCES; + if (!(flags & MS_RDONLY) && is_read_only(dev)) + goto out1; error = -EINVAL; sb = read_super(dev, bdev, fs_type, flags, data, 0); if (sb) { @@ -762,6 +773,7 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, path_release(&nd); return sb; } +out1: blkdev_put(bdev, BDEV_FS); } out: @@ -895,7 +907,7 @@ struct vfsmount *kern_mount(struct file_system_type *type) put_unnamed_dev(dev); return ERR_PTR(-EINVAL); } - mnt = add_vfsmnt(sb, sb->s_root, sb->s_root, NULL, "none", type->name); + mnt = add_vfsmnt(NULL, sb->s_root, "none"); if (!mnt) { kill_super(sb, 0); return ERR_PTR(-ENOMEM); @@ -909,10 +921,7 @@ struct vfsmount *kern_mount(struct file_system_type *type) void kern_umount(struct vfsmount *mnt) { struct super_block *sb = mnt->mnt_sb; - struct dentry *root = sb->s_root; remove_vfsmnt(mnt); - dput(root); - sb->s_root = NULL; kill_super(sb, 0); } @@ -932,6 +941,16 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) { struct super_block * sb = mnt->mnt_sb; + /* + * No sense to grab the lock for this test, but test itself looks + * somewhat bogus. Suggestions for better replacement? + * Ho-hum... In principle, we might treat that as umount + switch + * to rootfs. GC would eventually take care of the old vfsmount. + * The problem being: we have to implement rootfs and GC for that ;-) + * Actually it makes sense, especially if rootfs would contain a + * /reboot - static binary that would close all descriptors and + * call reboot(9). Then init(8) could umount root and exec /reboot. + */ if (mnt == current->fs->rootmnt && !umount_root) { int retval = 0; /* @@ -952,6 +971,7 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) if (mnt->mnt_instances.next != mnt->mnt_instances.prev) { if (sb->s_type->fs_flags & FS_SINGLE) put_filesystem(sb->s_type); + /* We hold two references, so mntput() is safe */ mntput(mnt); remove_vfsmnt(mnt); return 0; @@ -988,14 +1008,14 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) shrink_dcache_sb(sb); fsync_dev(sb->s_dev); - /* Something might grab it again - redo checks */ - - if (atomic_read(&mnt->mnt_count) > 2) { + if (sb->s_root->d_inode->i_state) { mntput(mnt); return -EBUSY; } - if (sb->s_root->d_inode->i_state) { + /* Something might grab it again - redo checks */ + + if (atomic_read(&mnt->mnt_count) > 2) { mntput(mnt); return -EBUSY; } @@ -1067,6 +1087,8 @@ static int mount_is_safe(struct nameidata *nd) { if (capable(CAP_SYS_ADMIN)) return 0; + return -EPERM; +#ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) return -EPERM; if (nd->dentry->d_inode->i_mode & S_ISVTX) { @@ -1076,6 +1098,7 @@ static int mount_is_safe(struct nameidata *nd) if (permission(nd->dentry->d_inode, MAY_WRITE)) return -EPERM; return 0; +#endif } /* @@ -1102,22 +1125,22 @@ static int do_loopback(char *old_name, char *new_name) if (S_ISDIR(new_nd.dentry->d_inode->i_mode) != S_ISDIR(old_nd.dentry->d_inode->i_mode)) goto out2; - - down(&mount_sem); - err = -ENOENT; - if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) - goto out3; - if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) - goto out3; - /* there we go */ + err = -ENOMEM; if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE) get_filesystem(old_nd.mnt->mnt_sb->s_type); - if (add_vfsmnt(old_nd.mnt->mnt_sb, new_nd.dentry, old_nd.dentry, - new_nd.mnt, old_nd.mnt->mnt_devname, new_name)) + + down(&mount_sem); + /* there we go */ + down(&new_nd.dentry->d_inode->i_zombie); + if (IS_DEADDIR(new_nd.dentry->d_inode)) + err = -ENOENT; + else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname)) err = 0; -out3: + up(&new_nd.dentry->d_inode->i_zombie); up(&mount_sem); + if (err && old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE) + put_filesystem(old_nd.mnt->mnt_sb->s_type); out2: path_release(&new_nd); out1: @@ -1215,7 +1238,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, { struct file_system_type * fstype; struct nameidata nd; - struct vfsmount *mnt; + struct vfsmount *mnt = NULL; struct super_block *sb; int retval = 0; unsigned long flags = 0; @@ -1224,8 +1247,6 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) return -EINVAL; - if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) - return -EINVAL; if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) return -EINVAL; @@ -1239,6 +1260,11 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) flags = new_flags & ~MS_MGC_MSK; + /* For the rest we need the type */ + + if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) + return -EINVAL; + /* loopback mount? This is special - requires fewer capabilities */ if (strcmp(type_page, "bind")==0) return do_loopback(dev_name, dir_name); @@ -1272,16 +1298,18 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (IS_ERR(sb)) goto dput_out; - retval = -ENOENT; - if (d_unhashed(nd.dentry) && !IS_ROOT(nd.dentry)) - goto fail; - /* Something was mounted here while we slept */ while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry)) ; - - retval = -ENOMEM; - mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, dev_name, dir_name); + retval = -ENOENT; + if (!nd.dentry->d_inode) + goto fail; + down(&nd.dentry->d_inode->i_zombie); + if (!IS_DEADDIR(nd.dentry->d_inode)) { + retval = -ENOMEM; + mnt = add_vfsmnt(&nd, sb->s_root, dev_name); + } + up(&nd.dentry->d_inode->i_zombie); if (!mnt) goto fail; retval = 0; @@ -1312,15 +1340,6 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, if (retval < 0) return retval; - /* copy_mount_options allows a NULL user pointer, - * and just returns zero in that case. But if we - * allow the type to be NULL we will crash. - * Previously we did not check this case. - */ - if (type_page == 0) - return -EINVAL; - - lock_kernel(); dir_page = getname(dir_name); retval = PTR_ERR(dir_page); if (IS_ERR(dir_page)) @@ -1331,8 +1350,10 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, goto out2; retval = copy_mount_options (data, &data_page); if (retval >= 0) { + lock_kernel(); retval = do_mount((char*)dev_page,dir_page,(char*)type_page, new_flags, (void*)data_page); + unlock_kernel(); free_page(data_page); } free_page(dev_page); @@ -1340,7 +1361,6 @@ out2: putname(dir_page); out1: free_page(type_page); - unlock_kernel(); return retval; } @@ -1490,12 +1510,11 @@ mount_it: path + 5 + path_start, 0, NULL, NULL); memcpy (path + path_start, "/dev/", 5); - vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL, - path + path_start, "/"); + vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start); } else - vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL, - "/dev/root", "/"); + vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root"); + /* FIXME: if something will try to umount us right now... */ if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); set_fs_pwd(current->fs, vfsmnt, sb->s_root); @@ -1516,6 +1535,7 @@ static void chroot_fs_refs(struct dentry *old_root, read_lock(&tasklist_lock); for_each_task(p) { + /* FIXME - unprotected usage of ->fs + (harmless) race */ if (!p->fs) continue; if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) set_fs_root(p->fs, new_rootmnt, new_root); @@ -1576,7 +1596,10 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) root_mnt = mntget(current->fs->rootmnt); root = dget(current->fs->root); down(&mount_sem); + down(&old_nd.dentry->d_inode->i_zombie); error = -ENOENT; + if (IS_DEADDIR(new_nd.dentry->d_inode)) + goto out2; if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) goto out2; if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) @@ -1599,19 +1622,12 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) } else if (!is_subdir(old_nd.dentry, new_nd.dentry)) goto out2; - error = -ENOMEM; - name = __getname(); - if (!name) - goto out2; - - move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/"); - move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL, - __d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry, - new_nd.mnt, name, PAGE_SIZE)); - putname(name); + move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL); + move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL); chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt); error = 0; out2: + up(&old_nd.dentry->d_inode->i_zombie); up(&mount_sem); dput(root); mntput(root_mnt); @@ -1629,10 +1645,11 @@ out0: int __init change_root(kdev_t new_root_dev,const char *put_old) { kdev_t old_root_dev = ROOT_DEV; - struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt); + struct vfsmount *old_rootmnt; struct nameidata devfs_nd, nd; int error = 0; + old_rootmnt = mntget(current->fs->rootmnt); /* First unmount devfs if mounted */ if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) error = path_walk("/dev", &devfs_nd); @@ -1675,7 +1692,8 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) printk(KERN_ERR "error %ld\n",blivet); return error; } - move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old); + /* FIXME: we should hold i_zombie on nd.dentry */ + move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old"); mntput(old_rootmnt); path_release(&nd); return 0; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 45581895975f..4f73a59ee3af 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -496,7 +496,6 @@ static struct super_block *sysv_read_super(struct super_block *sb, sb->s_blocksize = sb->sv_block_size; sb->s_blocksize_bits = sb->sv_block_size_bits; /* set up enough so that it can read an inode */ - sb->s_dev = dev; sb->s_op = &sysv_sops; root_inode = iget(sb,SYSV_ROOT_INO); sb->s_root = d_alloc_root(root_inode); diff --git a/fs/udf/super.c b/fs/udf/super.c index 5f76abbb0a0a..f3f575d7eba1 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1419,7 +1419,6 @@ udf_read_super(struct super_block *sb, void *options, int silent) return sb; error_out: - sb->s_dev = NODEV; if (UDF_SB_VAT(sb)) iput(UDF_SB_VAT(sb)); if (!(sb->s_flags & MS_RDONLY)) diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index a74290f55d72..86d1db58c506 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -51,10 +51,7 @@ struct pci_controler { #define PCIBIOS_MIN_IO alpha_mv.min_io_address #define PCIBIOS_MIN_MEM alpha_mv.min_mem_address -extern inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} +extern void pcibios_set_master(struct pci_dev *dev); extern inline void pcibios_penalize_isa_irq(int irq) { diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index 4c2f70170f48..6328750e1f35 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -14,16 +14,17 @@ * We leave one page for the initial stack page, and one page for * the initial process structure. Also, the console eats 3 MB for * the initial bootloader (one of which we can reclaim later). - * With a few other pages for various reasons, we'll use an initial - * load address of PAGE_OFFSET+0x310000UL */ #define BOOT_PCB 0x20000000 #define BOOT_ADDR 0x20000000 /* Remove when official MILO sources have ELF support: */ #define BOOT_SIZE (16*1024) - +#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS +#define KERNEL_START_PHYS 0x300000 /* Old bootloaders hardcoded this. */ +#else #define KERNEL_START_PHYS 0x800000 /* Wildfire has a huge console */ +#endif #define KERNEL_START (PAGE_OFFSET+KERNEL_START_PHYS) #define SWAPPER_PGD KERNEL_START diff --git a/include/asm-arm/arch-arc/ide.h b/include/asm-arm/arch-arc/ide.h index bccbe3f502ef..39f91b60bc3c 100644 --- a/include/asm-arm/arch-arc/ide.h +++ b/include/asm-arm/arch-arc/ide.h @@ -20,7 +20,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -30,7 +30,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* @@ -44,7 +45,8 @@ static __inline__ void ide_init_default_hwifs(void) memset(&hw, 0, sizeof(hw)); - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK); + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; ide_register_hw(&hw, NULL); #endif } diff --git a/include/asm-arm/arch-cl7500/ide.h b/include/asm-arm/arch-cl7500/ide.h index 590579747941..53daa0969571 100644 --- a/include/asm-arm/arch-cl7500/ide.h +++ b/include/asm-arm/arch-cl7500/ide.h @@ -13,7 +13,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -25,7 +25,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* diff --git a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h index 1a09f182779e..dbdeb1fab06f 100644 --- a/include/asm-arm/arch-ebsa285/ide.h +++ b/include/asm-arm/arch-ebsa285/ide.h @@ -13,7 +13,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -23,7 +23,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* diff --git a/include/asm-arm/arch-l7200/ide.h b/include/asm-arm/arch-l7200/ide.h index 0cfcf3aacb8d..aff8aaf9cf98 100644 --- a/include/asm-arm/arch-l7200/ide.h +++ b/include/asm-arm/arch-l7200/ide.h @@ -13,7 +13,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { } diff --git a/include/asm-arm/arch-nexuspci/ide.h b/include/asm-arm/arch-nexuspci/ide.h index cb1eac75a503..4a4d1b20cae2 100644 --- a/include/asm-arm/arch-nexuspci/ide.h +++ b/include/asm-arm/arch-nexuspci/ide.h @@ -13,7 +13,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -23,7 +23,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* diff --git a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h index ccbc7cf76aa6..827d81c2b7fc 100644 --- a/include/asm-arm/arch-rpc/ide.h +++ b/include/asm-arm/arch-rpc/ide.h @@ -13,7 +13,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -25,7 +25,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* @@ -37,6 +38,7 @@ ide_init_default_hwifs(void) { hw_regs_t hw; - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK); + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; ide_register_hw(&hw, NULL); } diff --git a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h index 3a1f00e3d0a2..3a9935c0b578 100644 --- a/include/asm-arm/arch-sa1100/ide.h +++ b/include/asm-arm/arch-sa1100/ide.h @@ -17,7 +17,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg; int i; @@ -37,7 +37,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += (1 << IO_SHIFT); } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) (ctrl_port << IO_SHIFT); - hw->irq = irq; + if (irq) + *irq = 0; } /* @@ -73,9 +74,11 @@ ide_init_default_hwifs(void) /* MAC 23/4/1999, swap these round so that the left hand hard disk is hda when viewed from the front. This doesn't match the silkscreen however. */ - ide_init_hwif_ports(&hw,0x10,0x1e,EMPEG_IRQ_IDE2); + ide_init_hwif_ports(&hw,0x10,0x1e,NULL); + hw.irq = EMPEG_IRQ_IDE2; ide_register_hw(&hw, NULL); - ide_init_hwif_ports(&hw,0x00,0x0e,EMPEG_IRQ_IDE1); + ide_init_hwif_ports(&hw,0x00,0x0e,NULL); + hw.irq = EMPEG_IRQ_IDE1; ide_register_hw(&hw, NULL); #elif defined( CONFIG_SA1100_VICTOR ) @@ -87,7 +90,8 @@ ide_init_default_hwifs(void) /* set the pcmcia interface timing */ MECR = 0x00060006; - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_GPIO7); + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_GPIO7; ide_register_hw(&hw, NULL); #else #error Missing IDE interface definition in include/asm/arch/ide.h diff --git a/include/asm-arm/arch-sa1100/irq.h b/include/asm-arm/arch-sa1100/irq.h index 6f447f497bad..2f1e63d82c67 100644 --- a/include/asm-arm/arch-sa1100/irq.h +++ b/include/asm-arm/arch-sa1100/irq.h @@ -15,6 +15,7 @@ * 26-05-2000 JD SA-1111 support added */ #include +#include #define fixup_irq(x) (x) @@ -73,7 +74,7 @@ static int GPIO_11_27_spurious; /* GPIOs that triggered when masked */ static void sa1100_GPIO11_27_demux(int irq, void *dev_id, struct pt_regs *regs) { - int i, irq, spurious; + int i, spurious; while( (irq = (GEDR & 0xfffff800)) ){ /* diff --git a/include/asm-arm/arch-shark/hardware.h b/include/asm-arm/arch-shark/hardware.h index 1fb25abd1e10..fc38d57aaa97 100644 --- a/include/asm-arm/arch-shark/hardware.h +++ b/include/asm-arm/arch-shark/hardware.h @@ -10,7 +10,7 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#ifndef __ASSEMBLER__ +#ifndef __ASSEMBLY__ /* * Mapping areas diff --git a/include/asm-arm/arch-shark/ide.h b/include/asm-arm/arch-shark/ide.h index a9e373e981e9..2ef90b55863f 100644 --- a/include/asm-arm/arch-shark/ide.h +++ b/include/asm-arm/arch-shark/ide.h @@ -15,7 +15,7 @@ * This should follow whatever the default interface uses. */ static __inline__ void -ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { ide_ioreg_t reg = (ide_ioreg_t) data_port; int i; @@ -27,7 +27,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) reg += 1; } hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - hw->irq = irq; + if (irq) + *irq = 0; } /* @@ -39,7 +40,8 @@ ide_init_default_hwifs(void) { hw_regs_t hw; - ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, 14); + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = 14; ide_register_hw(&hw, NULL); } diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h index d5dfe4f91258..94fd17170696 100644 --- a/include/asm-arm/atomic.h +++ b/include/asm-arm/atomic.h @@ -36,36 +36,36 @@ static __inline__ void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; - save_flags_cli (flags); + __save_flags_cli(flags); v->counter += i; - restore_flags (flags); + __restore_flags(flags); } static __inline__ void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; - save_flags_cli (flags); + __save_flags_cli(flags); v->counter -= i; - restore_flags (flags); + __restore_flags(flags); } static __inline__ void atomic_inc(volatile atomic_t *v) { unsigned long flags; - save_flags_cli (flags); + __save_flags_cli(flags); v->counter += 1; - restore_flags (flags); + __restore_flags(flags); } static __inline__ void atomic_dec(volatile atomic_t *v) { unsigned long flags; - save_flags_cli (flags); + __save_flags_cli(flags); v->counter -= 1; - restore_flags (flags); + __restore_flags(flags); } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) @@ -73,10 +73,10 @@ static __inline__ int atomic_dec_and_test(volatile atomic_t *v) unsigned long flags; int result; - save_flags_cli (flags); + __save_flags_cli(flags); v->counter -= 1; result = (v->counter == 0); - restore_flags (flags); + __restore_flags(flags); return result; } @@ -86,10 +86,10 @@ extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v) unsigned long flags; int result; - save_flags_cli(flags); + __save_flags_cli(flags); v->counter += i; result = (v->counter < 0); - restore_flags(flags); + __restore_flags(flags); return result; } @@ -98,9 +98,9 @@ static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *addr { unsigned long flags; - save_flags_cli (flags); + __save_flags_cli(flags); *addr &= ~mask; - restore_flags (flags); + __restore_flags(flags); } #endif diff --git a/include/asm-arm/cpu-multi26.h b/include/asm-arm/cpu-multi26.h index c09edf8b122d..50639037d8ae 100644 --- a/include/asm-arm/cpu-multi26.h +++ b/include/asm-arm/cpu-multi26.h @@ -20,7 +20,6 @@ extern struct processor { void (*_set_pgd)(pgd_t *pgd); /* XCHG */ unsigned long (*_xchg_1)(unsigned long x, volatile void *ptr); - unsigned long (*_xchg_2)(unsigned long x, volatile void *ptr); unsigned long (*_xchg_4)(unsigned long x, volatile void *ptr); } processor; @@ -34,7 +33,6 @@ extern const struct processor arm3_processor_functions; #define cpu_do_idle() do { } while (0) #define cpu_switch_mm(pgd,tsk) processor._set_pgd(pgd) #define cpu_xchg_1(x,ptr) processor._xchg_1(x,ptr) -#define cpu_xchg_2(x,ptr) processor._xchg_2(x,ptr) #define cpu_xchg_4(x,ptr) processor._xchg_4(x,ptr) extern void cpu_memc_update_all(pgd_t *pgd); diff --git a/include/asm-arm/dma.h b/include/asm-arm/dma.h index b67e33a9d6cc..67db9ab90c26 100644 --- a/include/asm-arm/dma.h +++ b/include/asm-arm/dma.h @@ -6,7 +6,8 @@ typedef unsigned int dmach_t; #include #include #include -#include +#include +#include #include /* diff --git a/include/asm-arm/floppy.h b/include/asm-arm/floppy.h index 9d98486440b8..05a94a2e6301 100644 --- a/include/asm-arm/floppy.h +++ b/include/asm-arm/floppy.h @@ -1,7 +1,9 @@ /* * linux/include/asm-arm/floppy.h * - * (C) 1996 Russell King + * (C) 1996-2000 Russell King + * + * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here */ #ifndef __ASM_ARM_FLOPPY_H #define __ASM_ARM_FLOPPY_H @@ -24,14 +26,14 @@ #define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK) #define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK) -#define fd_request_dma() request_dma(FLOPPY_DMA,"floppy") -#define fd_free_dma() free_dma(FLOPPY_DMA) -#define fd_disable_dma() disable_dma(FLOPPY_DMA) -#define fd_enable_dma() enable_dma(FLOPPY_DMA) -#define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA) -#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA, (mode)) -#define fd_set_dma_addr(addr) set_dma_addr(FLOPPY_DMA, virt_to_bus((addr))) -#define fd_set_dma_count(len) set_dma_count(FLOPPY_DMA, (len)) +#define fd_request_dma() request_dma(DMA_FLOPPY,"floppy") +#define fd_free_dma() free_dma(DMA_FLOPPY) +#define fd_disable_dma() disable_dma(DMA_FLOPPY) +#define fd_enable_dma() enable_dma(DMA_FLOPPY) +#define fd_clear_dma_ff() clear_dma_ff(DMA_FLOPPY) +#define fd_set_dma_mode(mode) set_dma_mode(DMA_FLOPPY, (mode)) +#define fd_set_dma_addr(addr) set_dma_addr(DMA_FLOPPY, virt_to_bus((addr))) +#define fd_set_dma_count(len) set_dma_count(DMA_FLOPPY, (len)) #define fd_cacheflush(addr,sz) /* need to clean up dma.h */ @@ -109,13 +111,12 @@ extern __inline__ void fd_scandrives (void) } #define FDC1 (0x3f0) -static int FDC2 = -1; #define FLOPPY0_TYPE 4 #define FLOPPY1_TYPE 4 #define N_FDC 1 -#define N_DRIVE 8 +#define N_DRIVE 4 #define FLOPPY_MOTOR_MASK 0xf0 diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 871e50a6517f..fad9e7412b24 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/io.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-2000 Russell King * * Modifications: * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both @@ -11,6 +11,7 @@ * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. * 04-Apr-1999 PJB Added check_signature. * 12-Dec-1999 RMK More cleanups + * 18-Jun-2000 RMK Removed virt_to_* and friends definitions */ #ifndef __ASM_ARM_IO_H #define __ASM_ARM_IO_H @@ -43,23 +44,7 @@ extern void insl(unsigned int port, void *from, int len); #ifdef __KERNEL__ -#include - -extern __inline__ unsigned long virt_to_phys(volatile void *x) -{ - return __virt_to_phys((unsigned long)(x)); -} - -extern __inline__ void *phys_to_virt(unsigned long x) -{ - return (void *)(__phys_to_virt((unsigned long)(x))); -} - -/* - * Virtual <-> DMA view memory address translations - */ -#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x))) -#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x)))) +#include /* the following macro is depreciated */ #define ioaddr(port) __ioaddr((port)) diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h new file mode 100644 index 000000000000..837ea199a023 --- /dev/null +++ b/include/asm-arm/memory.h @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/memory.h + * + * Copyright (C) 2000 Russell King + * + * Note: this file should not be included by non-asm/.h files + * + * Modifications: + */ +#ifndef __ASM_ARM_MEMORY_H +#define __ASM_ARM_MEMORY_H + +#include + +extern __inline__ unsigned long virt_to_phys(volatile void *x) +{ + return __virt_to_phys((unsigned long)(x)); +} + +extern __inline__ void *phys_to_virt(unsigned long x) +{ + return (void *)(__phys_to_virt((unsigned long)(x))); +} + +/* + * Virtual <-> DMA view memory address translations + */ +#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x))) +#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x)))) + +#endif diff --git a/include/asm-arm/proc-armo/system.h b/include/asm-arm/proc-armo/system.h index bc113ae6e2b5..36a3515e7a0d 100644 --- a/include/asm-arm/proc-armo/system.h +++ b/include/asm-arm/proc-armo/system.h @@ -7,20 +7,16 @@ #ifndef __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H -extern const char xchg_str[]; - -#include #include extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { - extern void arm_invalidptr(const char *, int); + extern void __bad_xchg(volatile void *, int); switch (size) { case 1: return cpu_xchg_1(x, ptr); - case 2: return cpu_xchg_2(x, ptr); case 4: return cpu_xchg_4(x, ptr); - default: arm_invalidptr(xchg_str, size); + default: __bad_xchg(ptr, size); } return 0; } @@ -108,22 +104,4 @@ extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int : "memory"); \ } while (0) -/* For spinlocks etc */ -#define local_irq_save(x) __save_flags_cli(x) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() - -#ifdef CONFIG_SMP -#error SMP not supported -#else - -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_flags_cli(x) __save_flags_cli(x) - -#endif - #endif diff --git a/include/asm-arm/proc-armv/system.h b/include/asm-arm/proc-armv/system.h index 3b35be30912c..d9ef8ffd98d8 100644 --- a/include/asm-arm/proc-armv/system.h +++ b/include/asm-arm/proc-armv/system.h @@ -7,20 +7,16 @@ #ifndef __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H -#include - -extern const char xchg_str[]; - extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { - extern void arm_invalidptr(const char *, int); + extern void __bad_xchg(volatile void *, int); switch (size) { case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory"); break; case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory"); break; - default: arm_invalidptr(xchg_str, size); + default: __bad_xchg(ptr, size); } return x; } @@ -102,22 +98,4 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ : "r" (x) \ : "memory") -/* For spinlocks etc */ -#define local_irq_save(x) __save_flags_cli(x) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() - -#ifdef CONFIG_SMP -#error SMP not supported -#else - -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_flags_cli(x) __save_flags_cli(x) - -#endif - #endif diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h index 961363cc71dc..3126767a4167 100644 --- a/include/asm-arm/ptrace.h +++ b/include/asm-arm/ptrace.h @@ -17,6 +17,10 @@ #ifdef __KERNEL__ extern void show_regs(struct pt_regs *); + +#define predicate(x) (x & 0xf0000000) +#define PREDICATE_ALWAYS 0xe0000000 + #endif #endif /* __ASSEMBLY__ */ diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index b75a88411bf8..94073475d127 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -381,7 +381,6 @@ extern unsigned int __machine_arch_type; #define tas(ptr) (xchg((ptr),1)) -extern void arm_malalignedptr(const char *, void *, volatile void *); extern asmlinkage void __backtrace(void); /* @@ -411,4 +410,22 @@ extern struct task_struct *__switch_to(struct task_struct *prev, struct task_str #endif +/* For spinlocks etc */ +#define local_irq_save(x) __save_flags_cli(x) +#define local_irq_restore(x) __restore_flags(x) +#define local_irq_disable() __cli() +#define local_irq_enable() __sti() + +#ifdef CONFIG_SMP +#error SMP not supported +#else + +#define cli() __cli() +#define sti() __sti() +#define save_flags(x) __save_flags(x) +#define restore_flags(x) __restore_flags(x) +#define save_flags_cli(x) __save_flags_cli(x) + +#endif + #endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 8a1f8e9b69be..3e7ace0916fe 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -47,7 +47,12 @@ struct poll_table_struct; #define BLOCK_SIZE (1<i_writecount); +} +static inline void allow_write_access(struct file *file) +{ + if (file) + atomic_inc(&file->f_dentry->d_inode->i_writecount); +} extern int do_pipe(int *); extern int open_namei(const char *, int, int, struct nameidata *); @@ -1037,7 +1051,7 @@ extern ino_t find_inode_number(struct dentry *, struct qstr *); /* * Type of the last component on LOOKUP_PARENT */ -enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT }; +enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; /* * "descriptor" for what we're up to with a read for sendfile(). @@ -1148,6 +1162,7 @@ extern struct inode_operations page_symlink_inode_operations; extern int vfs_readdir(struct file *, filldir_t, void *); extern int dcache_readdir(struct file *, void *, filldir_t); +extern struct file_system_type *get_fs_type(const char *name); extern struct super_block *get_super(kdev_t); struct super_block *get_empty_super(void); extern void put_super(kdev_t); @@ -1185,20 +1200,6 @@ extern void inode_setattr(struct inode *, struct iattr *); * */ -/* - * We need to do a check-parent every time - * after we have locked the parent - to verify - * that the parent is still our parent and - * that we are still hashed onto it.. - * - * This is required in case two processes race - * on removing (or moving) the same entry: the - * parent lock will serialize them, but the - * other process will be too late.. - */ -#define check_parent(dir, dentry) \ - ((dir) == (dentry)->d_parent && !d_unhashed(dentry)) - /* * Locking the parent is needed to: * - serialize directory operations diff --git a/include/linux/mm.h b/include/linux/mm.h index 37cb9664e2d3..e6325a2980d5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -185,6 +185,7 @@ typedef struct page { #define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags) #define PageDirty(page) test_bit(PG_dirty, &(page)->flags) #define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags) +#define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags) #define PageLocked(page) test_bit(PG_locked, &(page)->flags) #define LockPage(page) set_bit(PG_locked, &(page)->flags) #define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags) diff --git a/include/linux/mount.h b/include/linux/mount.h index 61ab19b1fc52..adb571de252e 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -26,7 +26,6 @@ struct vfsmount atomic_t mnt_count; char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ - char *mnt_dirname; /* Name of directory mounted on */ struct list_head mnt_list; uid_t mnt_owner; }; diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index 8e675705e77b..ae2da13bed23 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h @@ -25,9 +25,11 @@ struct svc_cacherep { unsigned char c_state, /* unused, inprog, done */ c_type, /* status, buffer */ c_secure : 1; /* req came from port < 1024 */ - struct in_addr c_client; + struct sockaddr_in c_addr; u32 c_xid; + u32 c_prot; u32 c_proc; + u32 c_vers; unsigned long c_timestamp; union { struct svc_buf u_buffer; diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 06a21296f965..5fb55c738323 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -95,18 +95,6 @@ int nfserrno(int errno); void exp_nlmdetach(void); -extern __inline__ int -exp_checkaddr(struct svc_client *clp, struct in_addr addr) -{ - struct in_addr *ap = clp->cl_addr; - int i; - - for (i = clp->cl_naddr; i--; ap++) - if (ap->s_addr == addr.s_addr) - return 1; - return 0; -} - #endif /* __KERNEL__ */ #endif /* NFSD_EXPORT_H */ diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 42663e79b86b..26e8edd22666 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -80,19 +80,19 @@ int nfsd_racache_init(int); void nfsd_racache_shutdown(void); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); -#ifdef CONFIG_NFSD_V3 -int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *); -#endif /* CONFIG_NFSD_V3 */ int nfsd_setattr(struct svc_rqst *, struct svc_fh *, struct iattr *); int nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, int type, dev_t rdev, struct svc_fh *res); #ifdef CONFIG_NFSD_V3 +int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *); int nfsd_create_v3(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, u32 *verifier); +int nfsd_commit(struct svc_rqst *, struct svc_fh *, + off_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ int nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file *); @@ -122,10 +122,7 @@ int nfsd_readdir(struct svc_rqst *, struct svc_fh *, u32 *buffer, int *countp, u32 *verf); int nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct statfs *); -#ifdef CONFIG_NFSD_V3 -int nfsd_commit(struct svc_rqst *, struct svc_fh *, - off_t, unsigned long); -#endif /* CONFIG_NFSD_V3 */ + int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 83320b810e4d..39ab97f14965 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h @@ -90,7 +90,7 @@ struct nfs_fhbase_new { }; struct knfsd_fh { - int fh_size; /* significant for NFSv3. + unsigned int fh_size; /* significant for NFSv3. * Points to the current size while building * a new file handle */ @@ -149,14 +149,13 @@ typedef struct svc_fh { struct dentry * fh_dentry; /* validated dentry */ struct svc_export * fh_export; /* export pointer */ int fh_maxsize; /* max size for fh_handle */ + + unsigned char fh_locked; /* inode locked by us */ + #ifdef CONFIG_NFSD_V3 unsigned char fh_post_saved; /* post-op attrs saved */ unsigned char fh_pre_saved; /* pre-op attrs saved */ -#endif /* CONFIG_NFSD_V3 */ - unsigned char fh_locked; /* inode locked by us */ - unsigned char fh_dverified; /* dentry has been checked */ -#ifdef CONFIG_NFSD_V3 /* Pre-op attributes saved during fh_lock */ __u64 fh_pre_size; /* size before operation */ time_t fh_pre_mtime; /* mtime before oper */ @@ -207,7 +206,7 @@ void fh_put(struct svc_fh *); static __inline__ struct svc_fh * fh_copy(struct svc_fh *dst, struct svc_fh *src) { - if (src->fh_dverified || src->fh_locked) { + if (src->fh_dentry || src->fh_locked) { struct dentry *dentry = src->fh_dentry; printk(KERN_ERR "fh_copy: copying %s/%s, already verified!\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -241,7 +240,6 @@ fill_pre_wcc(struct svc_fh *fhp) fhp->fh_pre_size = inode->i_size; fhp->fh_pre_saved = 1; } - fhp->fh_locked = 1; } /* @@ -273,13 +271,18 @@ fill_post_wcc(struct svc_fh *fhp) fhp->fh_post_mtime = inode->i_mtime; fhp->fh_post_ctime = inode->i_ctime; fhp->fh_post_saved = 1; - fhp->fh_locked = 0; } +#else +#define fill_pre_wcc(ignored) +#define fill_post_wcc(notused) #endif /* CONFIG_NFSD_V3 */ /* * Lock a file handle/inode + * NOTE: both fh_lock and fh_unlock are done "by hand" in + * vfs.c:nfsd_rename as it needs to grab 2 i_sem's at once + * so, any changes here should be reflected there. */ static inline void fh_lock(struct svc_fh *fhp) @@ -290,7 +293,7 @@ fh_lock(struct svc_fh *fhp) dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n", SVCFH_fmt(fhp), fhp->fh_locked); - if (!fhp->fh_dverified) { + if (!fhp->fh_dentry) { printk(KERN_ERR "fh_lock: fh not verified!\n"); return; } @@ -302,11 +305,8 @@ fh_lock(struct svc_fh *fhp) inode = dentry->d_inode; down(&inode->i_sem); -#ifdef CONFIG_NFSD_V3 fill_pre_wcc(fhp); -#else fhp->fh_locked = 1; -#endif /* CONFIG_NFSD_V3 */ } /* @@ -315,20 +315,13 @@ fh_lock(struct svc_fh *fhp) static inline void fh_unlock(struct svc_fh *fhp) { - if (!fhp->fh_dverified) + if (!fhp->fh_dentry) printk(KERN_ERR "fh_unlock: fh not verified!\n"); if (fhp->fh_locked) { -#ifdef CONFIG_NFSD_V3 fill_post_wcc(fhp); up(&fhp->fh_dentry->d_inode->i_sem); -#else - struct dentry *dentry = fhp->fh_dentry; - struct inode *inode = dentry->d_inode; - fhp->fh_locked = 0; - up(&inode->i_sem); -#endif /* CONFIG_NFSD_V3 */ } } #endif /* __KERNEL__ */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 61ac59d2a62b..5ccee05aaffd 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -329,13 +329,14 @@ #define PCI_DEVICE_ID_SI_6205 0x0205 #define PCI_DEVICE_ID_SI_501 0x0406 #define PCI_DEVICE_ID_SI_496 0x0496 -#define PCI_DEVICE_ID_SI_300 0x0300 +#define PCI_DEVICE_ID_SI_300 0x0300 #define PCI_DEVICE_ID_SI_530 0x0530 -#define PCI_DEVICE_ID_SI_540 0x5300 +#define PCI_DEVICE_ID_SI_540 0x0540 #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 -#define PCI_DEVICE_ID_SI_630 0x6300 +#define PCI_DEVICE_ID_SI_630 0x0630 #define PCI_DEVICE_ID_SI_5107 0x5107 +#define PCI_DEVICE_ID_SI_5300 0x5300 #define PCI_DEVICE_ID_SI_5511 0x5511 #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5571 0x5571 @@ -343,6 +344,7 @@ #define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_5598 0x5598 #define PCI_DEVICE_ID_SI_5600 0x5600 +#define PCI_DEVICE_ID_SI_6300 0x6300 #define PCI_DEVICE_ID_SI_6306 0x6306 #define PCI_DEVICE_ID_SI_6326 0x6326 #define PCI_DEVICE_ID_SI_7001 0x7001 diff --git a/include/linux/socket.h b/include/linux/socket.h index f3b8eefcc74f..f8c8f6b95524 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -128,19 +128,6 @@ struct ucred { __u32 gid; }; -/* Socket types. */ - -#define SOCK_STREAM 1 /* stream (connection) socket */ -#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ -#define SOCK_RAW 3 /* raw socket */ -#define SOCK_RDM 4 /* reliably-delivered message */ -#define SOCK_SEQPACKET 5 /* sequential packet socket */ -#define SOCK_PACKET 10 /* linux specific way of */ - /* getting packets at the dev */ - /* level. For writing rarp and */ - /* other similar things on the */ - /* user level. */ - /* Supported address families. */ #define AF_UNSPEC 0 #define AF_UNIX 1 /* Unix domain sockets */ diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 568a89a469d9..bba1e159e27a 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -20,10 +20,11 @@ struct vm_struct { extern struct vm_struct * get_vm_area (unsigned long size, unsigned long flags); extern void vfree(void * addr); -extern void * __vmalloc (unsigned long size, int gfp_mask); +extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot); extern long vread(char *buf, char *addr, unsigned long count); extern void vmfree_area_pages(unsigned long address, unsigned long size); -extern int vmalloc_area_pages(unsigned long address, unsigned long size , int gfp_mask); +extern int vmalloc_area_pages(unsigned long address, unsigned long size, + int gfp_mask, pgprot_t prot); extern struct vm_struct * vmlist; @@ -34,7 +35,7 @@ extern struct vm_struct * vmlist; static inline void * vmalloc (unsigned long size) { - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM); + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); } /* @@ -43,7 +44,7 @@ static inline void * vmalloc (unsigned long size) static inline void * vmalloc_dma (unsigned long size) { - return __vmalloc(size, GFP_KERNEL|GFP_DMA); + return __vmalloc(size, GFP_KERNEL|GFP_DMA, PAGE_KERNEL); } /* @@ -52,7 +53,7 @@ static inline void * vmalloc_dma (unsigned long size) static inline void * vmalloc_32(unsigned long size) { - return __vmalloc(size, GFP_KERNEL); + return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); } /* diff --git a/ipc/shm.c b/ipc/shm.c index f1b638acfda1..fac13b5421c0 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1490,7 +1490,7 @@ static int shm_swap_core(struct shmid_kernel *shp, unsigned long idx, swp_entry_ return RETRY; if (shp->id != zero_id) swap_attempts++; - if (--counter < 0) /* failed */ + if (--*counter < 0) /* failed */ return FAILED; if (page_count(page_map) != 1) return RETRY; diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c index 3f3b5fc16fd8..1daf64cc19b6 100644 --- a/kernel/exec_domain.c +++ b/kernel/exec_domain.c @@ -104,32 +104,37 @@ int unregister_exec_domain(struct exec_domain *it) void __set_personality(unsigned long personality) { - struct exec_domain *it; + struct exec_domain *it, *prev; it = lookup_exec_domain(personality); - if (it) { - if (atomic_read(¤t->fs->count) != 1) { - struct fs_struct *new = copy_fs_struct(current->fs); - struct fs_struct *old; - if (!new) { - put_exec_domain(it); - return; - } - task_lock(current); - old = current->fs; - current->fs = new; - task_unlock(current); - put_fs_struct(old); - } - /* - * At that point we are guaranteed to be the sole owner of - * current->fs. - */ + if (it == current->exec_domain) { current->personality = personality; - current->exec_domain = it; - set_fs_altroot(); - put_exec_domain(current->exec_domain); + return; + } + if (!it) + return; + if (atomic_read(¤t->fs->count) != 1) { + struct fs_struct *new = copy_fs_struct(current->fs); + struct fs_struct *old; + if (!new) { + put_exec_domain(it); + return; + } + task_lock(current); + old = current->fs; + current->fs = new; + task_unlock(current); + put_fs_struct(old); } + /* + * At that point we are guaranteed to be the sole owner of + * current->fs. + */ + current->personality = personality; + prev = current->exec_domain; + current->exec_domain = it; + set_fs_altroot(); + put_exec_domain(prev); } asmlinkage long sys_personality(unsigned long personality) diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 6a874a98264f..dc8a747e17c1 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -130,6 +130,7 @@ EXPORT_SYMBOL(highmem_start_page); /* filesystem internal functions */ EXPORT_SYMBOL(def_blk_fops); EXPORT_SYMBOL(update_atime); +EXPORT_SYMBOL(get_fs_type); EXPORT_SYMBOL(get_super); EXPORT_SYMBOL(get_empty_super); EXPORT_SYMBOL(getname); @@ -500,7 +501,6 @@ EXPORT_SYMBOL(disk_name); /* for md.c */ /* binfmt_aout */ EXPORT_SYMBOL(get_write_access); -EXPORT_SYMBOL(put_write_access); /* dynamic registering of consoles */ EXPORT_SYMBOL(register_console); diff --git a/kernel/module.c b/kernel/module.c index c0c5c9053fa5..5e5fbfe1b367 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -326,10 +326,11 @@ sys_init_module(const char *name_user, struct module *mod_user) /* Initialize the module. */ mod->flags |= MOD_INITIALIZING; atomic_set(&mod->uc.usecount,1); - if (mod->init && mod->init() != 0) { + if (mod->init && (error = mod->init()) != 0) { atomic_set(&mod->uc.usecount,0); mod->flags &= ~MOD_INITIALIZING; - error = -EBUSY; + if (error > 0) /* Buggy module */ + error = -EBUSY; goto err0; } atomic_dec(&mod->uc.usecount); diff --git a/kernel/sched.c b/kernel/sched.c index f85cc4213b8b..fa30b064581f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -60,8 +60,8 @@ struct task_struct * init_tasks[NR_CPUS] = {&init_task, }; * The run-queue lock locks the parts that actually access * and change the run-queues, and have to be interrupt-safe. */ -__cacheline_aligned spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; /* second */ -__cacheline_aligned rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; /* third */ +spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* second */ +rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* third */ static LIST_HEAD(runqueue_head); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5fc0418f966c..ab62787d1dfe 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -255,9 +255,9 @@ static ctl_table fs_table[] = { 0444, NULL, &proc_dointvec}, {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int), + {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_MAXFILE, "file-max", &max_files, sizeof(int), + {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int), 0644, NULL, &proc_dointvec}, {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int), 0444, NULL, &proc_dointvec}, diff --git a/mm/filemap.c b/mm/filemap.c index b1e2b8547fe6..360efacfbb9c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -195,6 +195,7 @@ repeat: * to it causing all sorts of fun problems ... */ remove_inode_page(page); + ClearPageDirty(page); UnlockPage(page); page_cache_release(page); @@ -500,7 +501,7 @@ void add_to_page_cache_locked(struct page * page, struct address_space *mapping, /* * This adds a page to the page cache, starting out as locked, - * owned by us, referenced, but not uptodate and with no errors. + * owned by us, but unreferenced, not uptodate and with no errors. */ static inline void __add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long offset, @@ -512,8 +513,8 @@ static inline void __add_to_page_cache(struct page * page, if (PageLocked(page)) BUG(); - flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty)); - page->flags = flags | (1 << PG_locked) | (1 << PG_referenced); + flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced)); + page->flags = flags | (1 << PG_locked); page_cache_get(page); page->index = offset; add_page_to_inode_queue(mapping, page); diff --git a/mm/mmap.c b/mm/mmap.c index f5bb2599c8d4..3d331a31179b 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -166,6 +166,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon { struct mm_struct * mm = current->mm; struct vm_area_struct * vma; + int correct_wcount = 0; int error; if (file && (!file->f_op || !file->f_op->mmap)) @@ -296,26 +297,15 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon goto free_vma; if (file) { - int correct_wcount = 0; if (vma->vm_flags & VM_DENYWRITE) { - if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) { - error = -ETXTBSY; + error = deny_write_access(file); + if (error) goto free_vma; - } - /* f_op->mmap might possibly sleep - * (generic_file_mmap doesn't, but other code - * might). In any case, this takes care of any - * race that this might cause. - */ - atomic_dec(&file->f_dentry->d_inode->i_writecount); correct_wcount = 1; } vma->vm_file = file; get_file(file); error = file->f_op->mmap(file, vma); - /* Fix up the count if necessary, then check for an error */ - if (correct_wcount) - atomic_inc(&file->f_dentry->d_inode->i_writecount); if (error) goto unmap_and_free_vma; } else if (flags & MAP_SHARED) { @@ -332,6 +322,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon addr = vma->vm_start; /* can addr have changed?? */ vmlist_modify_lock(mm); insert_vm_struct(mm, vma); + if (correct_wcount) + atomic_inc(&file->f_dentry->d_inode->i_writecount); merge_segments(mm, vma->vm_start, vma->vm_end); vmlist_modify_unlock(mm); @@ -343,6 +335,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon return addr; unmap_and_free_vma: + if (correct_wcount) + atomic_inc(&file->f_dentry->d_inode->i_writecount); vma->vm_file = NULL; fput(file); /* Undo any partial mapping done by a device driver. */ @@ -694,9 +688,11 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) * so release them, and unmap the page range.. * If the one of the segments is only being partially unmapped, * it will put new vm_area_struct(s) into the address space. + * In that case we have to be careful with VM_DENYWRITE. */ while ((mpnt = free) != NULL) { unsigned long st, end, size; + struct file *file = NULL; free = free->vm_next; @@ -708,6 +704,11 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) if (mpnt->vm_ops && mpnt->vm_ops->unmap) mpnt->vm_ops->unmap(mpnt, st, size); + if (mpnt->vm_flags & VM_DENYWRITE && + (st != mpnt->vm_start || end != mpnt->vm_end) && + (file = mpnt->vm_file) != NULL) { + atomic_dec(&file->f_dentry->d_inode->i_writecount); + } remove_shared_vm_struct(mpnt); mm->map_count--; @@ -719,6 +720,8 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) * Fix the mapping, and free the old area if it wasn't reused. */ extra = unmap_fixup(mm, mpnt, st, size, extra); + if (file) + atomic_inc(&file->f_dentry->d_inode->i_writecount); } /* Release the extra vma struct if it wasn't used */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 926364499a50..18a60fdbde60 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -93,6 +93,8 @@ void __free_pages_ok (struct page *page, unsigned long order) BUG(); if (PageDecrAfter(page)) BUG(); + if (PageDirty(page)) + BUG(); zone = page->zone; diff --git a/mm/swap_state.c b/mm/swap_state.c index 2405aba2ffbf..72f3eaca49b3 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -58,8 +58,8 @@ void add_to_swap_cache(struct page *page, swp_entry_t entry) BUG(); if (page->mapping) BUG(); - flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty)); - page->flags = flags | (1 << PG_referenced) | (1 << PG_uptodate); + flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced)); + page->flags = flags | (1 << PG_uptodate); add_to_page_cache_locked(page, &swapper_space, entry.val); } diff --git a/mm/swapfile.c b/mm/swapfile.c index 55ef476a38a0..5d3a7f23e802 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -407,11 +407,11 @@ asmlinkage long sys_swapoff(const char * specialfile) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); err = user_path_walk(specialfile, &nd); if (err) goto out; + lock_kernel(); prev = -1; swap_list_lock(); for (type = swap_list.head; type >= 0; type = swap_info[type].next) { @@ -478,9 +478,9 @@ asmlinkage long sys_swapoff(const char * specialfile) err = 0; out_dput: + unlock_kernel(); path_release(&nd); out: - unlock_kernel(); return err; } @@ -555,7 +555,6 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags) unsigned long maxpages; int swapfilesize; struct block_device *bdev = NULL; - char *name; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -586,14 +585,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags) } else { p->prio = --least_priority; } - name = getname(specialfile); - error = PTR_ERR(name); - if (IS_ERR(name)) - goto bad_swap_2; - error = 0; - if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) - error = path_walk(name, &nd); - putname(name); + error = user_path_walk(specialfile, &nd); if (error) goto bad_swap_2; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index b3f1cf5b76e0..57f3ca56cc7e 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -91,7 +91,7 @@ void vmfree_area_pages(unsigned long address, unsigned long size) } static inline int alloc_area_pte (pte_t * pte, unsigned long address, - unsigned long size, int gfp_mask) + unsigned long size, int gfp_mask, pgprot_t prot) { unsigned long end; @@ -106,14 +106,14 @@ static inline int alloc_area_pte (pte_t * pte, unsigned long address, page = alloc_page(gfp_mask); if (!page) return -ENOMEM; - set_pte(pte, mk_pte(page, PAGE_KERNEL)); + set_pte(pte, mk_pte(page, prot)); address += PAGE_SIZE; pte++; } while (address < end); return 0; } -static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask) +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot) { unsigned long end; @@ -125,7 +125,7 @@ static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo pte_t * pte = pte_alloc_kernel(pmd, address); if (!pte) return -ENOMEM; - if (alloc_area_pte(pte, address, end - address, gfp_mask)) + if (alloc_area_pte(pte, address, end - address, gfp_mask, prot)) return -ENOMEM; address = (address + PMD_SIZE) & PMD_MASK; pmd++; @@ -133,8 +133,8 @@ static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo return 0; } -inline int vmalloc_area_pages (unsigned long address, - unsigned long size, int gfp_mask) +inline int vmalloc_area_pages (unsigned long address, unsigned long size, + int gfp_mask, pgprot_t prot) { pgd_t * dir; unsigned long end = address + size; @@ -148,7 +148,7 @@ inline int vmalloc_area_pages (unsigned long address, pmd = pmd_alloc_kernel(dir, address); if (!pmd) return -ENOMEM; - if (alloc_area_pmd(pmd, address, end - address, gfp_mask)) + if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot)) return -ENOMEM; if (pgd_val(olddir) != pgd_val(*dir)) set_pgdir(address, *dir); @@ -212,7 +212,7 @@ void vfree(void * addr) printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); } -void * __vmalloc (unsigned long size, int gfp_mask) +void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot) { void * addr; struct vm_struct *area; @@ -228,7 +228,7 @@ void * __vmalloc (unsigned long size, int gfp_mask) return NULL; } addr = area->addr; - if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask)) { + if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) { vfree(addr); BUG(); return NULL; diff --git a/net/netsyms.c b/net/netsyms.c index c209ff9910f2..cd4a2bdb9247 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -196,7 +196,7 @@ EXPORT_SYMBOL(__scm_send); /* Needed by unix.o */ EXPORT_SYMBOL(scm_fp_dup); -EXPORT_SYMBOL(max_files); +EXPORT_SYMBOL(files_stat); EXPORT_SYMBOL(memcpy_toiovec); EXPORT_SYMBOL(csum_partial); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index e0a13d725926..f0f714ff0e84 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -371,6 +372,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) dprintk("svc: recvfrom returned error %d\n", -err); } + if (skb->ip_summed != CHECKSUM_UNNECESSARY) { + unsigned int csum = skb->csum; + csum = csum_partial(skb->h.raw, skb->len, csum); + if ((unsigned short)csum_fold(csum)) { + skb_free_datagram(svsk->sk_sk, skb); + svc_sock_received(svsk, 0); + return 0; + } + } + /* There may be more data */ svsk->sk_data = 1; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index d71a527fe2f5..20e0fc8c72bc 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -445,7 +445,7 @@ static struct sock * unix_create1(struct socket *sock) { struct sock *sk; - if (atomic_read(&unix_nr_socks) >= 2*max_files) + if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files) return NULL; MOD_INC_USE_COUNT; -- 2.39.5